aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/core
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/Kconfig133
-rw-r--r--sound/core/Makefile33
-rw-r--r--sound/core/control.c1375
-rw-r--r--sound/core/control_compat.c412
-rw-r--r--sound/core/device.c240
-rw-r--r--sound/core/hwdep.c524
-rw-r--r--sound/core/hwdep_compat.c77
-rw-r--r--sound/core/info.c989
-rw-r--r--sound/core/info_oss.c137
-rw-r--r--sound/core/init.c887
-rw-r--r--sound/core/isadma.c103
-rw-r--r--sound/core/memalloc.c663
-rw-r--r--sound/core/memory.c306
-rw-r--r--sound/core/misc.c76
-rw-r--r--sound/core/oss/Makefile12
-rw-r--r--sound/core/oss/copy.c87
-rw-r--r--sound/core/oss/io.c134
-rw-r--r--sound/core/oss/linear.c158
-rw-r--r--sound/core/oss/mixer_oss.c1340
-rw-r--r--sound/core/oss/mulaw.c308
-rw-r--r--sound/core/oss/pcm_oss.c2530
-rw-r--r--sound/core/oss/pcm_plugin.c921
-rw-r--r--sound/core/oss/pcm_plugin.h250
-rw-r--r--sound/core/oss/plugin_ops.h536
-rw-r--r--sound/core/oss/rate.c378
-rw-r--r--sound/core/oss/route.c519
-rw-r--r--sound/core/pcm.c1074
-rw-r--r--sound/core/pcm_compat.c513
-rw-r--r--sound/core/pcm_lib.c2612
-rw-r--r--sound/core/pcm_memory.c363
-rw-r--r--sound/core/pcm_misc.c481
-rw-r--r--sound/core/pcm_native.c3364
-rw-r--r--sound/core/pcm_timer.c161
-rw-r--r--sound/core/rawmidi.c1680
-rw-r--r--sound/core/rawmidi_compat.c120
-rw-r--r--sound/core/rtctimer.c188
-rw-r--r--sound/core/seq/Makefile44
-rw-r--r--sound/core/seq/instr/Makefile23
-rw-r--r--sound/core/seq/instr/ainstr_fm.c156
-rw-r--r--sound/core/seq/instr/ainstr_gf1.c358
-rw-r--r--sound/core/seq/instr/ainstr_iw.c622
-rw-r--r--sound/core/seq/instr/ainstr_simple.c215
-rw-r--r--sound/core/seq/oss/Makefile10
-rw-r--r--sound/core/seq/oss/seq_oss.c317
-rw-r--r--sound/core/seq/oss/seq_oss_device.h198
-rw-r--r--sound/core/seq/oss/seq_oss_event.c447
-rw-r--r--sound/core/seq/oss/seq_oss_event.h112
-rw-r--r--sound/core/seq/oss/seq_oss_init.c555
-rw-r--r--sound/core/seq/oss/seq_oss_ioctl.c209
-rw-r--r--sound/core/seq/oss/seq_oss_midi.c710
-rw-r--r--sound/core/seq/oss/seq_oss_midi.h49
-rw-r--r--sound/core/seq/oss/seq_oss_readq.c234
-rw-r--r--sound/core/seq/oss/seq_oss_readq.h56
-rw-r--r--sound/core/seq/oss/seq_oss_rw.c216
-rw-r--r--sound/core/seq/oss/seq_oss_synth.c659
-rw-r--r--sound/core/seq/oss/seq_oss_synth.h49
-rw-r--r--sound/core/seq/oss/seq_oss_timer.c283
-rw-r--r--sound/core/seq/oss/seq_oss_timer.h70
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.c170
-rw-r--r--sound/core/seq/oss/seq_oss_writeq.h50
-rw-r--r--sound/core/seq/seq.c147
-rw-r--r--sound/core/seq/seq_clientmgr.c2503
-rw-r--r--sound/core/seq/seq_clientmgr.h104
-rw-r--r--sound/core/seq/seq_compat.c137
-rw-r--r--sound/core/seq/seq_device.c575
-rw-r--r--sound/core/seq/seq_dummy.c273
-rw-r--r--sound/core/seq/seq_fifo.c264
-rw-r--r--sound/core/seq/seq_fifo.h72
-rw-r--r--sound/core/seq/seq_info.c75
-rw-r--r--sound/core/seq/seq_info.h36
-rw-r--r--sound/core/seq/seq_instr.c653
-rw-r--r--sound/core/seq/seq_lock.c48
-rw-r--r--sound/core/seq/seq_lock.h33
-rw-r--r--sound/core/seq/seq_memory.c510
-rw-r--r--sound/core/seq/seq_memory.h104
-rw-r--r--sound/core/seq/seq_midi.c489
-rw-r--r--sound/core/seq/seq_midi_emul.c735
-rw-r--r--sound/core/seq/seq_midi_event.c539
-rw-r--r--sound/core/seq/seq_ports.c674
-rw-r--r--sound/core/seq/seq_ports.h128
-rw-r--r--sound/core/seq/seq_prioq.c449
-rw-r--r--sound/core/seq/seq_prioq.h62
-rw-r--r--sound/core/seq/seq_queue.c783
-rw-r--r--sound/core/seq/seq_queue.h140
-rw-r--r--sound/core/seq/seq_system.c190
-rw-r--r--sound/core/seq/seq_system.h46
-rw-r--r--sound/core/seq/seq_timer.c435
-rw-r--r--sound/core/seq/seq_timer.h141
-rw-r--r--sound/core/seq/seq_virmidi.c551
-rw-r--r--sound/core/sgbuf.c111
-rw-r--r--sound/core/sound.c491
-rw-r--r--sound/core/sound_oss.c250
-rw-r--r--sound/core/timer.c1901
-rw-r--r--sound/core/timer_compat.c119
-rw-r--r--sound/core/wrappers.c50
95 files changed, 43314 insertions, 0 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
new file mode 100644
index 000000000000..d1e800b9866d
--- /dev/null
+++ b/sound/core/Kconfig
@@ -0,0 +1,133 @@
1# ALSA soundcard-configuration
2config SND_TIMER
3 tristate
4 depends on SND
5
6config SND_PCM
7 tristate
8 select SND_TIMER
9 depends on SND
10
11config SND_HWDEP
12 tristate
13 depends on SND
14
15config SND_RAWMIDI
16 tristate
17 depends on SND
18
19config SND_SEQUENCER
20 tristate "Sequencer support"
21 depends on SND
22 select SND_TIMER
23 help
24 Say Y or M to enable MIDI sequencer and router support. This
25 feature allows routing and enqueueing of MIDI events. Events
26 can be processed at a given time.
27
28 Many programs require this feature, so you should enable it
29 unless you know what you're doing.
30
31config SND_SEQ_DUMMY
32 tristate "Sequencer dummy client"
33 depends on SND_SEQUENCER
34 help
35 Say Y here to enable the dummy sequencer client. This client
36 is a simple MIDI-through client: all normal input events are
37 redirected to the output port immediately.
38
39 You don't need this unless you want to connect many MIDI
40 devices or applications together.
41
42 To compile this driver as a module, choose M here: the module
43 will be called snd-seq-dummy.
44
45config SND_OSSEMUL
46 bool
47 depends on SND
48
49config SND_MIXER_OSS
50 tristate "OSS Mixer API"
51 depends on SND
52 select SND_OSSEMUL
53 help
54 To enable OSS mixer API emulation (/dev/mixer*), say Y here
55 and read <file:Documentation/sound/alsa/OSS-Emulation.txt>.
56
57 Many programs still use the OSS API, so say Y.
58
59 To compile this driver as a module, choose M here: the module
60 will be called snd-mixer-oss.
61
62config SND_PCM_OSS
63 tristate "OSS PCM (digital audio) API"
64 depends on SND
65 select SND_OSSEMUL
66 select SND_PCM
67 help
68 To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y
69 here and read <file:Documentation/sound/alsa/OSS-Emulation.txt>.
70
71 Many programs still use the OSS API, so say Y.
72
73 To compile this driver as a module, choose M here: the module
74 will be called snd-pcm-oss.
75
76config SND_SEQUENCER_OSS
77 bool "OSS Sequencer API"
78 depends on SND && SND_SEQUENCER
79 select SND_OSSEMUL
80 help
81 Say Y here to enable OSS sequencer emulation (both
82 /dev/sequencer and /dev/music interfaces).
83
84 Many programs still use the OSS API, so say Y.
85
86 To compile this driver as a module, choose M here: the module
87 will be called snd-seq-oss.
88
89config SND_RTCTIMER
90 tristate "RTC Timer support"
91 depends on SND && RTC
92 select SND_TIMER
93 help
94 Say Y here to enable RTC timer support for ALSA. ALSA uses
95 the RTC timer as a precise timing source and maps the RTC
96 timer to ALSA's timer interface. The ALSA sequencer code also
97 can use this timing source.
98
99 To compile this driver as a module, choose M here: the module
100 will be called snd-rtctimer.
101
102config SND_VERBOSE_PRINTK
103 bool "Verbose printk"
104 depends on SND
105 help
106 Say Y here to enable verbose log messages. These messages
107 will help to identify source file and position containing
108 printed messages.
109
110 You don't need this unless you're debugging ALSA.
111
112config SND_DEBUG
113 bool "Debug"
114 depends on SND
115 help
116 Say Y here to enable ALSA debug code.
117
118config SND_DEBUG_MEMORY
119 bool "Debug memory"
120 depends on SND_DEBUG
121 help
122 Say Y here to enable debugging of memory allocations.
123
124config SND_DEBUG_DETECT
125 bool "Debug detection"
126 depends on SND_DEBUG
127 help
128 Say Y here to enable extra-verbose log messages printed when
129 detecting devices.
130
131config SND_GENERIC_PM
132 bool
133 depends on SND
diff --git a/sound/core/Makefile b/sound/core/Makefile
new file mode 100644
index 000000000000..764ac184b223
--- /dev/null
+++ b/sound/core/Makefile
@@ -0,0 +1,33 @@
1#
2# Makefile for ALSA
3# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-objs := sound.o init.o memory.o info.o control.o misc.o \
7 device.o wrappers.o
8ifeq ($(CONFIG_ISA),y)
9snd-objs += isadma.o
10endif
11ifeq ($(CONFIG_SND_OSSEMUL),y)
12snd-objs += sound_oss.o info_oss.o
13endif
14
15snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
16 pcm_memory.o
17
18snd-page-alloc-objs := memalloc.o sgbuf.o
19
20snd-rawmidi-objs := rawmidi.o
21snd-timer-objs := timer.o
22snd-rtctimer-objs := rtctimer.o
23snd-hwdep-objs := hwdep.o
24
25obj-$(CONFIG_SND) += snd.o
26obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o
27obj-$(CONFIG_SND_TIMER) += snd-timer.o
28obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o
29obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o
30obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o
31
32obj-$(CONFIG_SND_OSSEMUL) += oss/
33obj-$(CONFIG_SND_SEQUENCER) += seq/
diff --git a/sound/core/control.c b/sound/core/control.c
new file mode 100644
index 000000000000..f4ea6bff1dd3
--- /dev/null
+++ b/sound/core/control.c
@@ -0,0 +1,1375 @@
1/*
2 * Routines for driver control interface
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/threads.h>
24#include <linux/interrupt.h>
25#include <linux/smp_lock.h>
26#include <linux/slab.h>
27#include <linux/vmalloc.h>
28#include <linux/time.h>
29#include <sound/core.h>
30#include <sound/minors.h>
31#include <sound/info.h>
32#include <sound/control.h>
33
34/* max number of user-defined controls */
35#define MAX_USER_CONTROLS 32
36
37typedef struct _snd_kctl_ioctl {
38 struct list_head list; /* list of all ioctls */
39 snd_kctl_ioctl_func_t fioctl;
40} snd_kctl_ioctl_t;
41
42#define snd_kctl_ioctl(n) list_entry(n, snd_kctl_ioctl_t, list)
43
44static DECLARE_RWSEM(snd_ioctl_rwsem);
45static LIST_HEAD(snd_control_ioctls);
46#ifdef CONFIG_COMPAT
47static LIST_HEAD(snd_control_compat_ioctls);
48#endif
49
50static int snd_ctl_open(struct inode *inode, struct file *file)
51{
52 int cardnum = SNDRV_MINOR_CARD(iminor(inode));
53 unsigned long flags;
54 snd_card_t *card;
55 snd_ctl_file_t *ctl;
56 int err;
57
58 card = snd_cards[cardnum];
59 if (!card) {
60 err = -ENODEV;
61 goto __error1;
62 }
63 err = snd_card_file_add(card, file);
64 if (err < 0) {
65 err = -ENODEV;
66 goto __error1;
67 }
68 if (!try_module_get(card->module)) {
69 err = -EFAULT;
70 goto __error2;
71 }
72 ctl = kcalloc(1, sizeof(*ctl), GFP_KERNEL);
73 if (ctl == NULL) {
74 err = -ENOMEM;
75 goto __error;
76 }
77 INIT_LIST_HEAD(&ctl->events);
78 init_waitqueue_head(&ctl->change_sleep);
79 spin_lock_init(&ctl->read_lock);
80 ctl->card = card;
81 ctl->pid = current->pid;
82 file->private_data = ctl;
83 write_lock_irqsave(&card->ctl_files_rwlock, flags);
84 list_add_tail(&ctl->list, &card->ctl_files);
85 write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
86 return 0;
87
88 __error:
89 module_put(card->module);
90 __error2:
91 snd_card_file_remove(card, file);
92 __error1:
93 return err;
94}
95
96static void snd_ctl_empty_read_queue(snd_ctl_file_t * ctl)
97{
98 snd_kctl_event_t *cread;
99
100 spin_lock(&ctl->read_lock);
101 while (!list_empty(&ctl->events)) {
102 cread = snd_kctl_event(ctl->events.next);
103 list_del(&cread->list);
104 kfree(cread);
105 }
106 spin_unlock(&ctl->read_lock);
107}
108
109static int snd_ctl_release(struct inode *inode, struct file *file)
110{
111 unsigned long flags;
112 struct list_head *list;
113 snd_card_t *card;
114 snd_ctl_file_t *ctl;
115 snd_kcontrol_t *control;
116 unsigned int idx;
117
118 ctl = file->private_data;
119 fasync_helper(-1, file, 0, &ctl->fasync);
120 file->private_data = NULL;
121 card = ctl->card;
122 write_lock_irqsave(&card->ctl_files_rwlock, flags);
123 list_del(&ctl->list);
124 write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
125 down_write(&card->controls_rwsem);
126 list_for_each(list, &card->controls) {
127 control = snd_kcontrol(list);
128 for (idx = 0; idx < control->count; idx++)
129 if (control->vd[idx].owner == ctl)
130 control->vd[idx].owner = NULL;
131 }
132 up_write(&card->controls_rwsem);
133 snd_ctl_empty_read_queue(ctl);
134 kfree(ctl);
135 module_put(card->module);
136 snd_card_file_remove(card, file);
137 return 0;
138}
139
140void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id)
141{
142 unsigned long flags;
143 struct list_head *flist;
144 snd_ctl_file_t *ctl;
145 snd_kctl_event_t *ev;
146
147 snd_runtime_check(card != NULL && id != NULL, return);
148 read_lock(&card->ctl_files_rwlock);
149#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
150 card->mixer_oss_change_count++;
151#endif
152 list_for_each(flist, &card->ctl_files) {
153 struct list_head *elist;
154 ctl = snd_ctl_file(flist);
155 if (!ctl->subscribed)
156 continue;
157 spin_lock_irqsave(&ctl->read_lock, flags);
158 list_for_each(elist, &ctl->events) {
159 ev = snd_kctl_event(elist);
160 if (ev->id.numid == id->numid) {
161 ev->mask |= mask;
162 goto _found;
163 }
164 }
165 ev = kcalloc(1, sizeof(*ev), GFP_ATOMIC);
166 if (ev) {
167 ev->id = *id;
168 ev->mask = mask;
169 list_add_tail(&ev->list, &ctl->events);
170 } else {
171 snd_printk(KERN_ERR "No memory available to allocate event\n");
172 }
173 _found:
174 wake_up(&ctl->change_sleep);
175 spin_unlock_irqrestore(&ctl->read_lock, flags);
176 kill_fasync(&ctl->fasync, SIGIO, POLL_IN);
177 }
178 read_unlock(&card->ctl_files_rwlock);
179}
180
181/**
182 * snd_ctl_new - create a control instance from the template
183 * @control: the control template
184 * @access: the default control access
185 *
186 * Allocates a new snd_kcontrol_t instance and copies the given template
187 * to the new instance. It does not copy volatile data (access).
188 *
189 * Returns the pointer of the new instance, or NULL on failure.
190 */
191snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access)
192{
193 snd_kcontrol_t *kctl;
194 unsigned int idx;
195
196 snd_runtime_check(control != NULL, return NULL);
197 snd_runtime_check(control->count > 0, return NULL);
198 kctl = kcalloc(1, sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL);
199 if (kctl == NULL)
200 return NULL;
201 *kctl = *control;
202 for (idx = 0; idx < kctl->count; idx++)
203 kctl->vd[idx].access = access;
204 return kctl;
205}
206
207/**
208 * snd_ctl_new1 - create a control instance from the template
209 * @ncontrol: the initialization record
210 * @private_data: the private data to set
211 *
212 * Allocates a new snd_kcontrol_t instance and initialize from the given
213 * template. When the access field of ncontrol is 0, it's assumed as
214 * READWRITE access. When the count field is 0, it's assumes as one.
215 *
216 * Returns the pointer of the newly generated instance, or NULL on failure.
217 */
218snd_kcontrol_t *snd_ctl_new1(snd_kcontrol_new_t * ncontrol, void *private_data)
219{
220 snd_kcontrol_t kctl;
221 unsigned int access;
222
223 snd_runtime_check(ncontrol != NULL, return NULL);
224 snd_assert(ncontrol->info != NULL, return NULL);
225 memset(&kctl, 0, sizeof(kctl));
226 kctl.id.iface = ncontrol->iface;
227 kctl.id.device = ncontrol->device;
228 kctl.id.subdevice = ncontrol->subdevice;
229 if (ncontrol->name)
230 strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
231 kctl.id.index = ncontrol->index;
232 kctl.count = ncontrol->count ? ncontrol->count : 1;
233 access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
234 (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE|
235 SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT));
236 kctl.info = ncontrol->info;
237 kctl.get = ncontrol->get;
238 kctl.put = ncontrol->put;
239 kctl.private_value = ncontrol->private_value;
240 kctl.private_data = private_data;
241 return snd_ctl_new(&kctl, access);
242}
243
244/**
245 * snd_ctl_free_one - release the control instance
246 * @kcontrol: the control instance
247 *
248 * Releases the control instance created via snd_ctl_new()
249 * or snd_ctl_new1().
250 * Don't call this after the control was added to the card.
251 */
252void snd_ctl_free_one(snd_kcontrol_t * kcontrol)
253{
254 if (kcontrol) {
255 if (kcontrol->private_free)
256 kcontrol->private_free(kcontrol);
257 kfree(kcontrol);
258 }
259}
260
261static unsigned int snd_ctl_hole_check(snd_card_t * card,
262 unsigned int count)
263{
264 struct list_head *list;
265 snd_kcontrol_t *kctl;
266
267 list_for_each(list, &card->controls) {
268 kctl = snd_kcontrol(list);
269 if ((kctl->id.numid <= card->last_numid &&
270 kctl->id.numid + kctl->count > card->last_numid) ||
271 (kctl->id.numid <= card->last_numid + count - 1 &&
272 kctl->id.numid + kctl->count > card->last_numid + count - 1))
273 return card->last_numid = kctl->id.numid + kctl->count - 1;
274 }
275 return card->last_numid;
276}
277
278static int snd_ctl_find_hole(snd_card_t * card, unsigned int count)
279{
280 unsigned int last_numid, iter = 100000;
281
282 last_numid = card->last_numid;
283 while (last_numid != snd_ctl_hole_check(card, count)) {
284 if (--iter == 0) {
285 /* this situation is very unlikely */
286 snd_printk(KERN_ERR "unable to allocate new control numid\n");
287 return -ENOMEM;
288 }
289 last_numid = card->last_numid;
290 }
291 return 0;
292}
293
294/**
295 * snd_ctl_add - add the control instance to the card
296 * @card: the card instance
297 * @kcontrol: the control instance to add
298 *
299 * Adds the control instance created via snd_ctl_new() or
300 * snd_ctl_new1() to the given card. Assigns also an unique
301 * numid used for fast search.
302 *
303 * Returns zero if successful, or a negative error code on failure.
304 *
305 * It frees automatically the control which cannot be added.
306 */
307int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol)
308{
309 snd_ctl_elem_id_t id;
310 unsigned int idx;
311
312 snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL);
313 snd_assert(kcontrol->info != NULL, return -EINVAL);
314 id = kcontrol->id;
315 down_write(&card->controls_rwsem);
316 if (snd_ctl_find_id(card, &id)) {
317 up_write(&card->controls_rwsem);
318 snd_ctl_free_one(kcontrol);
319 snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
320 id.iface,
321 id.device,
322 id.subdevice,
323 id.name,
324 id.index);
325 return -EBUSY;
326 }
327 if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
328 up_write(&card->controls_rwsem);
329 snd_ctl_free_one(kcontrol);
330 return -ENOMEM;
331 }
332 list_add_tail(&kcontrol->list, &card->controls);
333 card->controls_count += kcontrol->count;
334 kcontrol->id.numid = card->last_numid + 1;
335 card->last_numid += kcontrol->count;
336 up_write(&card->controls_rwsem);
337 for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
338 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
339 return 0;
340}
341
342/**
343 * snd_ctl_remove - remove the control from the card and release it
344 * @card: the card instance
345 * @kcontrol: the control instance to remove
346 *
347 * Removes the control from the card and then releases the instance.
348 * You don't need to call snd_ctl_free_one(). You must be in
349 * the write lock - down_write(&card->controls_rwsem).
350 *
351 * Returns 0 if successful, or a negative error code on failure.
352 */
353int snd_ctl_remove(snd_card_t * card, snd_kcontrol_t * kcontrol)
354{
355 snd_ctl_elem_id_t id;
356 unsigned int idx;
357
358 snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL);
359 list_del(&kcontrol->list);
360 card->controls_count -= kcontrol->count;
361 id = kcontrol->id;
362 for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
363 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id);
364 snd_ctl_free_one(kcontrol);
365 return 0;
366}
367
368/**
369 * snd_ctl_remove_id - remove the control of the given id and release it
370 * @card: the card instance
371 * @id: the control id to remove
372 *
373 * Finds the control instance with the given id, removes it from the
374 * card list and releases it.
375 *
376 * Returns 0 if successful, or a negative error code on failure.
377 */
378int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id)
379{
380 snd_kcontrol_t *kctl;
381 int ret;
382
383 down_write(&card->controls_rwsem);
384 kctl = snd_ctl_find_id(card, id);
385 if (kctl == NULL) {
386 up_write(&card->controls_rwsem);
387 return -ENOENT;
388 }
389 ret = snd_ctl_remove(card, kctl);
390 up_write(&card->controls_rwsem);
391 return ret;
392}
393
394/**
395 * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it
396 * @file: active control handle
397 * @id: the control id to remove
398 *
399 * Finds the control instance with the given id, removes it from the
400 * card list and releases it.
401 *
402 * Returns 0 if successful, or a negative error code on failure.
403 */
404static int snd_ctl_remove_unlocked_id(snd_ctl_file_t * file, snd_ctl_elem_id_t *id)
405{
406 snd_card_t *card = file->card;
407 snd_kcontrol_t *kctl;
408 int idx, ret;
409
410 down_write(&card->controls_rwsem);
411 kctl = snd_ctl_find_id(card, id);
412 if (kctl == NULL) {
413 up_write(&card->controls_rwsem);
414 return -ENOENT;
415 }
416 for (idx = 0; idx < kctl->count; idx++)
417 if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
418 up_write(&card->controls_rwsem);
419 return -EBUSY;
420 }
421 ret = snd_ctl_remove(card, kctl);
422 up_write(&card->controls_rwsem);
423 return ret;
424}
425
426/**
427 * snd_ctl_rename_id - replace the id of a control on the card
428 * @card: the card instance
429 * @src_id: the old id
430 * @dst_id: the new id
431 *
432 * Finds the control with the old id from the card, and replaces the
433 * id with the new one.
434 *
435 * Returns zero if successful, or a negative error code on failure.
436 */
437int snd_ctl_rename_id(snd_card_t * card, snd_ctl_elem_id_t *src_id, snd_ctl_elem_id_t *dst_id)
438{
439 snd_kcontrol_t *kctl;
440
441 down_write(&card->controls_rwsem);
442 kctl = snd_ctl_find_id(card, src_id);
443 if (kctl == NULL) {
444 up_write(&card->controls_rwsem);
445 return -ENOENT;
446 }
447 kctl->id = *dst_id;
448 kctl->id.numid = card->last_numid + 1;
449 card->last_numid += kctl->count;
450 up_write(&card->controls_rwsem);
451 return 0;
452}
453
454/**
455 * snd_ctl_find_numid - find the control instance with the given number-id
456 * @card: the card instance
457 * @numid: the number-id to search
458 *
459 * Finds the control instance with the given number-id from the card.
460 *
461 * Returns the pointer of the instance if found, or NULL if not.
462 *
463 * The caller must down card->controls_rwsem before calling this function
464 * (if the race condition can happen).
465 */
466snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid)
467{
468 struct list_head *list;
469 snd_kcontrol_t *kctl;
470
471 snd_runtime_check(card != NULL && numid != 0, return NULL);
472 list_for_each(list, &card->controls) {
473 kctl = snd_kcontrol(list);
474 if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
475 return kctl;
476 }
477 return NULL;
478}
479
480/**
481 * snd_ctl_find_id - find the control instance with the given id
482 * @card: the card instance
483 * @id: the id to search
484 *
485 * Finds the control instance with the given id from the card.
486 *
487 * Returns the pointer of the instance if found, or NULL if not.
488 *
489 * The caller must down card->controls_rwsem before calling this function
490 * (if the race condition can happen).
491 */
492snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id)
493{
494 struct list_head *list;
495 snd_kcontrol_t *kctl;
496
497 snd_runtime_check(card != NULL && id != NULL, return NULL);
498 if (id->numid != 0)
499 return snd_ctl_find_numid(card, id->numid);
500 list_for_each(list, &card->controls) {
501 kctl = snd_kcontrol(list);
502 if (kctl->id.iface != id->iface)
503 continue;
504 if (kctl->id.device != id->device)
505 continue;
506 if (kctl->id.subdevice != id->subdevice)
507 continue;
508 if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))
509 continue;
510 if (kctl->id.index > id->index)
511 continue;
512 if (kctl->id.index + kctl->count <= id->index)
513 continue;
514 return kctl;
515 }
516 return NULL;
517}
518
519static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
520 unsigned int cmd, void __user *arg)
521{
522 snd_ctl_card_info_t *info;
523
524 info = kcalloc(1, sizeof(*info), GFP_KERNEL);
525 if (! info)
526 return -ENOMEM;
527 down_read(&snd_ioctl_rwsem);
528 info->card = card->number;
529 strlcpy(info->id, card->id, sizeof(info->id));
530 strlcpy(info->driver, card->driver, sizeof(info->driver));
531 strlcpy(info->name, card->shortname, sizeof(info->name));
532 strlcpy(info->longname, card->longname, sizeof(info->longname));
533 strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
534 strlcpy(info->components, card->components, sizeof(info->components));
535 up_read(&snd_ioctl_rwsem);
536 if (copy_to_user(arg, info, sizeof(snd_ctl_card_info_t))) {
537 kfree(info);
538 return -EFAULT;
539 }
540 kfree(info);
541 return 0;
542}
543
544static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list)
545{
546 struct list_head *plist;
547 snd_ctl_elem_list_t list;
548 snd_kcontrol_t *kctl;
549 snd_ctl_elem_id_t *dst, *id;
550 unsigned int offset, space, first, jidx;
551
552 if (copy_from_user(&list, _list, sizeof(list)))
553 return -EFAULT;
554 offset = list.offset;
555 space = list.space;
556 first = 0;
557 /* try limit maximum space */
558 if (space > 16384)
559 return -ENOMEM;
560 if (space > 0) {
561 /* allocate temporary buffer for atomic operation */
562 dst = vmalloc(space * sizeof(snd_ctl_elem_id_t));
563 if (dst == NULL)
564 return -ENOMEM;
565 down_read(&card->controls_rwsem);
566 list.count = card->controls_count;
567 plist = card->controls.next;
568 while (plist != &card->controls) {
569 if (offset == 0)
570 break;
571 kctl = snd_kcontrol(plist);
572 if (offset < kctl->count)
573 break;
574 offset -= kctl->count;
575 plist = plist->next;
576 }
577 list.used = 0;
578 id = dst;
579 while (space > 0 && plist != &card->controls) {
580 kctl = snd_kcontrol(plist);
581 for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
582 snd_ctl_build_ioff(id, kctl, jidx);
583 id++;
584 space--;
585 list.used++;
586 }
587 plist = plist->next;
588 offset = 0;
589 }
590 up_read(&card->controls_rwsem);
591 if (list.used > 0 && copy_to_user(list.pids, dst, list.used * sizeof(snd_ctl_elem_id_t))) {
592 vfree(dst);
593 return -EFAULT;
594 }
595 vfree(dst);
596 } else {
597 down_read(&card->controls_rwsem);
598 list.count = card->controls_count;
599 up_read(&card->controls_rwsem);
600 }
601 if (copy_to_user(_list, &list, sizeof(list)))
602 return -EFAULT;
603 return 0;
604}
605
606static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *info)
607{
608 snd_card_t *card = ctl->card;
609 snd_kcontrol_t *kctl;
610 snd_kcontrol_volatile_t *vd;
611 unsigned int index_offset;
612 int result;
613
614 down_read(&card->controls_rwsem);
615 kctl = snd_ctl_find_id(card, &info->id);
616 if (kctl == NULL) {
617 up_read(&card->controls_rwsem);
618 return -ENOENT;
619 }
620#ifdef CONFIG_SND_DEBUG
621 info->access = 0;
622#endif
623 result = kctl->info(kctl, info);
624 if (result >= 0) {
625 snd_assert(info->access == 0, );
626 index_offset = snd_ctl_get_ioff(kctl, &info->id);
627 vd = &kctl->vd[index_offset];
628 snd_ctl_build_ioff(&info->id, kctl, index_offset);
629 info->access = vd->access;
630 if (vd->owner) {
631 info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
632 if (vd->owner == ctl)
633 info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
634 info->owner = vd->owner_pid;
635 } else {
636 info->owner = -1;
637 }
638 }
639 up_read(&card->controls_rwsem);
640 return result;
641}
642
643static int snd_ctl_elem_info_user(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
644{
645 snd_ctl_elem_info_t info;
646 int result;
647
648 if (copy_from_user(&info, _info, sizeof(info)))
649 return -EFAULT;
650 result = snd_ctl_elem_info(ctl, &info);
651 if (result >= 0)
652 if (copy_to_user(_info, &info, sizeof(info)))
653 return -EFAULT;
654 return result;
655}
656
657int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *control)
658{
659 snd_kcontrol_t *kctl;
660 snd_kcontrol_volatile_t *vd;
661 unsigned int index_offset;
662 int result, indirect;
663
664 down_read(&card->controls_rwsem);
665 kctl = snd_ctl_find_id(card, &control->id);
666 if (kctl == NULL) {
667 result = -ENOENT;
668 } else {
669 index_offset = snd_ctl_get_ioff(kctl, &control->id);
670 vd = &kctl->vd[index_offset];
671 indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
672 if (control->indirect != indirect) {
673 result = -EACCES;
674 } else {
675 if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {
676 snd_ctl_build_ioff(&control->id, kctl, index_offset);
677 result = kctl->get(kctl, control);
678 } else {
679 result = -EPERM;
680 }
681 }
682 }
683 up_read(&card->controls_rwsem);
684 return result;
685}
686
687static int snd_ctl_elem_read_user(snd_card_t *card, snd_ctl_elem_value_t __user *_control)
688{
689 snd_ctl_elem_value_t *control;
690 int result;
691
692 control = kmalloc(sizeof(*control), GFP_KERNEL);
693 if (control == NULL)
694 return -ENOMEM;
695 if (copy_from_user(control, _control, sizeof(*control))) {
696 kfree(control);
697 return -EFAULT;
698 }
699 result = snd_ctl_elem_read(card, control);
700 if (result >= 0)
701 if (copy_to_user(_control, control, sizeof(*control)))
702 result = -EFAULT;
703 kfree(control);
704 return result;
705}
706
707int snd_ctl_elem_write(snd_card_t *card, snd_ctl_file_t *file, snd_ctl_elem_value_t *control)
708{
709 snd_kcontrol_t *kctl;
710 snd_kcontrol_volatile_t *vd;
711 unsigned int index_offset;
712 int result, indirect;
713
714 down_read(&card->controls_rwsem);
715 kctl = snd_ctl_find_id(card, &control->id);
716 if (kctl == NULL) {
717 result = -ENOENT;
718 } else {
719 index_offset = snd_ctl_get_ioff(kctl, &control->id);
720 vd = &kctl->vd[index_offset];
721 indirect = vd->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
722 if (control->indirect != indirect) {
723 result = -EACCES;
724 } else {
725 if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
726 kctl->put == NULL ||
727 (file && vd->owner != NULL && vd->owner != file)) {
728 result = -EPERM;
729 } else {
730 snd_ctl_build_ioff(&control->id, kctl, index_offset);
731 result = kctl->put(kctl, control);
732 }
733 if (result > 0) {
734 up_read(&card->controls_rwsem);
735 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &control->id);
736 return 0;
737 }
738 }
739 }
740 up_read(&card->controls_rwsem);
741 return result;
742}
743
744static int snd_ctl_elem_write_user(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control)
745{
746 snd_ctl_elem_value_t *control;
747 int result;
748
749 control = kmalloc(sizeof(*control), GFP_KERNEL);
750 if (control == NULL)
751 return -ENOMEM;
752 if (copy_from_user(control, _control, sizeof(*control))) {
753 kfree(control);
754 return -EFAULT;
755 }
756 result = snd_ctl_elem_write(file->card, file, control);
757 if (result >= 0)
758 if (copy_to_user(_control, control, sizeof(*control)))
759 result = -EFAULT;
760 kfree(control);
761 return result;
762}
763
764static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
765{
766 snd_card_t *card = file->card;
767 snd_ctl_elem_id_t id;
768 snd_kcontrol_t *kctl;
769 snd_kcontrol_volatile_t *vd;
770 int result;
771
772 if (copy_from_user(&id, _id, sizeof(id)))
773 return -EFAULT;
774 down_write(&card->controls_rwsem);
775 kctl = snd_ctl_find_id(card, &id);
776 if (kctl == NULL) {
777 result = -ENOENT;
778 } else {
779 vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
780 if (vd->owner != NULL)
781 result = -EBUSY;
782 else {
783 vd->owner = file;
784 vd->owner_pid = current->pid;
785 result = 0;
786 }
787 }
788 up_write(&card->controls_rwsem);
789 return result;
790}
791
792static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
793{
794 snd_card_t *card = file->card;
795 snd_ctl_elem_id_t id;
796 snd_kcontrol_t *kctl;
797 snd_kcontrol_volatile_t *vd;
798 int result;
799
800 if (copy_from_user(&id, _id, sizeof(id)))
801 return -EFAULT;
802 down_write(&card->controls_rwsem);
803 kctl = snd_ctl_find_id(card, &id);
804 if (kctl == NULL) {
805 result = -ENOENT;
806 } else {
807 vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
808 if (vd->owner == NULL)
809 result = -EINVAL;
810 else if (vd->owner != file)
811 result = -EPERM;
812 else {
813 vd->owner = NULL;
814 vd->owner_pid = 0;
815 result = 0;
816 }
817 }
818 up_write(&card->controls_rwsem);
819 return result;
820}
821
822struct user_element {
823 snd_ctl_elem_info_t info;
824 void *elem_data; /* element data */
825 unsigned long elem_data_size; /* size of element data in bytes */
826 void *priv_data; /* private data (like strings for enumerated type) */
827 unsigned long priv_data_size; /* size of private data in bytes */
828};
829
830static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
831{
832 struct user_element *ue = kcontrol->private_data;
833
834 *uinfo = ue->info;
835 return 0;
836}
837
838static int snd_ctl_elem_user_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
839{
840 struct user_element *ue = kcontrol->private_data;
841
842 memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
843 return 0;
844}
845
846static int snd_ctl_elem_user_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
847{
848 int change;
849 struct user_element *ue = kcontrol->private_data;
850
851 change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
852 if (change)
853 memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
854 return change;
855}
856
857static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol)
858{
859 kfree(kcontrol->private_data);
860}
861
862static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int replace)
863{
864 snd_card_t *card = file->card;
865 snd_kcontrol_t kctl, *_kctl;
866 unsigned int access;
867 long private_size;
868 struct user_element *ue;
869 int idx, err;
870
871 if (card->user_ctl_count >= MAX_USER_CONTROLS)
872 return -ENOMEM;
873 if (info->count > 1024)
874 return -EINVAL;
875 access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
876 (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE));
877 info->id.numid = 0;
878 memset(&kctl, 0, sizeof(kctl));
879 down_write(&card->controls_rwsem);
880 _kctl = snd_ctl_find_id(card, &info->id);
881 err = 0;
882 if (_kctl) {
883 if (replace)
884 err = snd_ctl_remove(card, _kctl);
885 else
886 err = -EBUSY;
887 } else {
888 if (replace)
889 err = -ENOENT;
890 }
891 up_write(&card->controls_rwsem);
892 if (err < 0)
893 return err;
894 memcpy(&kctl.id, &info->id, sizeof(info->id));
895 kctl.count = info->owner ? info->owner : 1;
896 access |= SNDRV_CTL_ELEM_ACCESS_USER;
897 kctl.info = snd_ctl_elem_user_info;
898 if (access & SNDRV_CTL_ELEM_ACCESS_READ)
899 kctl.get = snd_ctl_elem_user_get;
900 if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
901 kctl.put = snd_ctl_elem_user_put;
902 switch (info->type) {
903 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
904 private_size = sizeof(char);
905 if (info->count > 128)
906 return -EINVAL;
907 break;
908 case SNDRV_CTL_ELEM_TYPE_INTEGER:
909 private_size = sizeof(long);
910 if (info->count > 128)
911 return -EINVAL;
912 break;
913 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
914 private_size = sizeof(long long);
915 if (info->count > 64)
916 return -EINVAL;
917 break;
918 case SNDRV_CTL_ELEM_TYPE_BYTES:
919 private_size = sizeof(unsigned char);
920 if (info->count > 512)
921 return -EINVAL;
922 break;
923 case SNDRV_CTL_ELEM_TYPE_IEC958:
924 private_size = sizeof(struct sndrv_aes_iec958);
925 if (info->count != 1)
926 return -EINVAL;
927 break;
928 default:
929 return -EINVAL;
930 }
931 private_size *= info->count;
932 ue = kcalloc(1, sizeof(struct user_element) + private_size, GFP_KERNEL);
933 if (ue == NULL)
934 return -ENOMEM;
935 ue->info = *info;
936 ue->elem_data = (char *)ue + sizeof(*ue);
937 ue->elem_data_size = private_size;
938 kctl.private_free = snd_ctl_elem_user_free;
939 _kctl = snd_ctl_new(&kctl, access);
940 if (_kctl == NULL) {
941 kfree(_kctl->private_data);
942 return -ENOMEM;
943 }
944 _kctl->private_data = ue;
945 for (idx = 0; idx < _kctl->count; idx++)
946 _kctl->vd[idx].owner = file;
947 err = snd_ctl_add(card, _kctl);
948 if (err < 0) {
949 snd_ctl_free_one(_kctl);
950 return err;
951 }
952
953 down_write(&card->controls_rwsem);
954 card->user_ctl_count++;
955 up_write(&card->controls_rwsem);
956
957 return 0;
958}
959
960static int snd_ctl_elem_add_user(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
961{
962 snd_ctl_elem_info_t info;
963 if (copy_from_user(&info, _info, sizeof(info)))
964 return -EFAULT;
965 return snd_ctl_elem_add(file, &info, replace);
966}
967
968static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
969{
970 snd_ctl_elem_id_t id;
971 int err;
972
973 if (copy_from_user(&id, _id, sizeof(id)))
974 return -EFAULT;
975 err = snd_ctl_remove_unlocked_id(file, &id);
976 if (! err) {
977 snd_card_t *card = file->card;
978 down_write(&card->controls_rwsem);
979 card->user_ctl_count--;
980 up_write(&card->controls_rwsem);
981 }
982 return err;
983}
984
985static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr)
986{
987 int subscribe;
988 if (get_user(subscribe, ptr))
989 return -EFAULT;
990 if (subscribe < 0) {
991 subscribe = file->subscribed;
992 if (put_user(subscribe, ptr))
993 return -EFAULT;
994 return 0;
995 }
996 if (subscribe) {
997 file->subscribed = 1;
998 return 0;
999 } else if (file->subscribed) {
1000 snd_ctl_empty_read_queue(file);
1001 file->subscribed = 0;
1002 }
1003 return 0;
1004}
1005
1006#ifdef CONFIG_PM
1007/*
1008 * change the power state
1009 */
1010static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state)
1011{
1012 switch (power_state) {
1013 case SNDRV_CTL_POWER_D0:
1014 if (card->power_state != power_state) {
1015 card->pm_resume(card);
1016 snd_power_change_state(card, power_state);
1017 }
1018 break;
1019 case SNDRV_CTL_POWER_D3hot:
1020 if (card->power_state != power_state) {
1021 card->pm_suspend(card, PMSG_SUSPEND);
1022 snd_power_change_state(card, power_state);
1023 }
1024 break;
1025 case SNDRV_CTL_POWER_D1:
1026 case SNDRV_CTL_POWER_D2:
1027 case SNDRV_CTL_POWER_D3cold:
1028 /* not supported yet */
1029 default:
1030 return -EINVAL;
1031 }
1032 return 0;
1033}
1034#endif
1035
1036static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1037{
1038 snd_ctl_file_t *ctl;
1039 snd_card_t *card;
1040 struct list_head *list;
1041 snd_kctl_ioctl_t *p;
1042 void __user *argp = (void __user *)arg;
1043 int __user *ip = argp;
1044 int err;
1045
1046 ctl = file->private_data;
1047 card = ctl->card;
1048 snd_assert(card != NULL, return -ENXIO);
1049 switch (cmd) {
1050 case SNDRV_CTL_IOCTL_PVERSION:
1051 return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
1052 case SNDRV_CTL_IOCTL_CARD_INFO:
1053 return snd_ctl_card_info(card, ctl, cmd, argp);
1054 case SNDRV_CTL_IOCTL_ELEM_LIST:
1055 return snd_ctl_elem_list(ctl->card, argp);
1056 case SNDRV_CTL_IOCTL_ELEM_INFO:
1057 return snd_ctl_elem_info_user(ctl, argp);
1058 case SNDRV_CTL_IOCTL_ELEM_READ:
1059 return snd_ctl_elem_read_user(ctl->card, argp);
1060 case SNDRV_CTL_IOCTL_ELEM_WRITE:
1061 return snd_ctl_elem_write_user(ctl, argp);
1062 case SNDRV_CTL_IOCTL_ELEM_LOCK:
1063 return snd_ctl_elem_lock(ctl, argp);
1064 case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
1065 return snd_ctl_elem_unlock(ctl, argp);
1066 case SNDRV_CTL_IOCTL_ELEM_ADD:
1067 return snd_ctl_elem_add_user(ctl, argp, 0);
1068 case SNDRV_CTL_IOCTL_ELEM_REPLACE:
1069 return snd_ctl_elem_add_user(ctl, argp, 1);
1070 case SNDRV_CTL_IOCTL_ELEM_REMOVE:
1071 return snd_ctl_elem_remove(ctl, argp);
1072 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
1073 return snd_ctl_subscribe_events(ctl, ip);
1074 case SNDRV_CTL_IOCTL_POWER:
1075 if (get_user(err, ip))
1076 return -EFAULT;
1077 if (!capable(CAP_SYS_ADMIN))
1078 return -EPERM;
1079#ifdef CONFIG_PM
1080 if (card->pm_suspend && card->pm_resume) {
1081 snd_power_lock(card);
1082 err = snd_ctl_set_power_state(card, err);
1083 snd_power_unlock(card);
1084 } else
1085#endif
1086 err = -ENOPROTOOPT;
1087 return err;
1088 case SNDRV_CTL_IOCTL_POWER_STATE:
1089#ifdef CONFIG_PM
1090 return put_user(card->power_state, ip) ? -EFAULT : 0;
1091#else
1092 return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
1093#endif
1094 }
1095 down_read(&snd_ioctl_rwsem);
1096 list_for_each(list, &snd_control_ioctls) {
1097 p = list_entry(list, snd_kctl_ioctl_t, list);
1098 err = p->fioctl(card, ctl, cmd, arg);
1099 if (err != -ENOIOCTLCMD) {
1100 up_read(&snd_ioctl_rwsem);
1101 return err;
1102 }
1103 }
1104 up_read(&snd_ioctl_rwsem);
1105 snd_printd("unknown ioctl = 0x%x\n", cmd);
1106 return -ENOTTY;
1107}
1108
1109static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset)
1110{
1111 snd_ctl_file_t *ctl;
1112 int err = 0;
1113 ssize_t result = 0;
1114
1115 ctl = file->private_data;
1116 snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
1117 if (!ctl->subscribed)
1118 return -EBADFD;
1119 if (count < sizeof(snd_ctl_event_t))
1120 return -EINVAL;
1121 spin_lock_irq(&ctl->read_lock);
1122 while (count >= sizeof(snd_ctl_event_t)) {
1123 snd_ctl_event_t ev;
1124 snd_kctl_event_t *kev;
1125 while (list_empty(&ctl->events)) {
1126 wait_queue_t wait;
1127 if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
1128 err = -EAGAIN;
1129 goto __end_lock;
1130 }
1131 init_waitqueue_entry(&wait, current);
1132 add_wait_queue(&ctl->change_sleep, &wait);
1133 set_current_state(TASK_INTERRUPTIBLE);
1134 spin_unlock_irq(&ctl->read_lock);
1135 schedule();
1136 remove_wait_queue(&ctl->change_sleep, &wait);
1137 if (signal_pending(current))
1138 return result > 0 ? result : -ERESTARTSYS;
1139 spin_lock_irq(&ctl->read_lock);
1140 }
1141 kev = snd_kctl_event(ctl->events.next);
1142 ev.type = SNDRV_CTL_EVENT_ELEM;
1143 ev.data.elem.mask = kev->mask;
1144 ev.data.elem.id = kev->id;
1145 list_del(&kev->list);
1146 spin_unlock_irq(&ctl->read_lock);
1147 kfree(kev);
1148 if (copy_to_user(buffer, &ev, sizeof(snd_ctl_event_t))) {
1149 err = -EFAULT;
1150 goto __end;
1151 }
1152 spin_lock_irq(&ctl->read_lock);
1153 buffer += sizeof(snd_ctl_event_t);
1154 count -= sizeof(snd_ctl_event_t);
1155 result += sizeof(snd_ctl_event_t);
1156 }
1157 __end_lock:
1158 spin_unlock_irq(&ctl->read_lock);
1159 __end:
1160 return result > 0 ? result : err;
1161}
1162
1163static unsigned int snd_ctl_poll(struct file *file, poll_table * wait)
1164{
1165 unsigned int mask;
1166 snd_ctl_file_t *ctl;
1167
1168 ctl = file->private_data;
1169 if (!ctl->subscribed)
1170 return 0;
1171 poll_wait(file, &ctl->change_sleep, wait);
1172
1173 mask = 0;
1174 if (!list_empty(&ctl->events))
1175 mask |= POLLIN | POLLRDNORM;
1176
1177 return mask;
1178}
1179
1180/*
1181 * register the device-specific control-ioctls.
1182 * called from each device manager like pcm.c, hwdep.c, etc.
1183 */
1184static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
1185{
1186 snd_kctl_ioctl_t *pn;
1187
1188 pn = kcalloc(1, sizeof(snd_kctl_ioctl_t), GFP_KERNEL);
1189 if (pn == NULL)
1190 return -ENOMEM;
1191 pn->fioctl = fcn;
1192 down_write(&snd_ioctl_rwsem);
1193 list_add_tail(&pn->list, lists);
1194 up_write(&snd_ioctl_rwsem);
1195 return 0;
1196}
1197
1198int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
1199{
1200 return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
1201}
1202
1203#ifdef CONFIG_COMPAT
1204int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
1205{
1206 return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
1207}
1208#endif
1209
1210/*
1211 * de-register the device-specific control-ioctls.
1212 */
1213static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
1214{
1215 struct list_head *list;
1216 snd_kctl_ioctl_t *p;
1217
1218 snd_runtime_check(fcn != NULL, return -EINVAL);
1219 down_write(&snd_ioctl_rwsem);
1220 list_for_each(list, lists) {
1221 p = list_entry(list, snd_kctl_ioctl_t, list);
1222 if (p->fioctl == fcn) {
1223 list_del(&p->list);
1224 up_write(&snd_ioctl_rwsem);
1225 kfree(p);
1226 return 0;
1227 }
1228 }
1229 up_write(&snd_ioctl_rwsem);
1230 snd_BUG();
1231 return -EINVAL;
1232}
1233
1234int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
1235{
1236 return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
1237}
1238
1239#ifdef CONFIG_COMPAT
1240int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
1241{
1242 return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
1243}
1244
1245#endif
1246
1247static int snd_ctl_fasync(int fd, struct file * file, int on)
1248{
1249 snd_ctl_file_t *ctl;
1250 int err;
1251 ctl = file->private_data;
1252 err = fasync_helper(fd, file, on, &ctl->fasync);
1253 if (err < 0)
1254 return err;
1255 return 0;
1256}
1257
1258/*
1259 * ioctl32 compat
1260 */
1261#ifdef CONFIG_COMPAT
1262#include "control_compat.c"
1263#else
1264#define snd_ctl_ioctl_compat NULL
1265#endif
1266
1267/*
1268 * INIT PART
1269 */
1270
1271static struct file_operations snd_ctl_f_ops =
1272{
1273 .owner = THIS_MODULE,
1274 .read = snd_ctl_read,
1275 .open = snd_ctl_open,
1276 .release = snd_ctl_release,
1277 .poll = snd_ctl_poll,
1278 .unlocked_ioctl = snd_ctl_ioctl,
1279 .compat_ioctl = snd_ctl_ioctl_compat,
1280 .fasync = snd_ctl_fasync,
1281};
1282
1283static snd_minor_t snd_ctl_reg =
1284{
1285 .comment = "ctl",
1286 .f_ops = &snd_ctl_f_ops,
1287};
1288
1289/*
1290 * registration of the control device
1291 */
1292static int snd_ctl_dev_register(snd_device_t *device)
1293{
1294 snd_card_t *card = device->device_data;
1295 int err, cardnum;
1296 char name[16];
1297
1298 snd_assert(card != NULL, return -ENXIO);
1299 cardnum = card->number;
1300 snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
1301 sprintf(name, "controlC%i", cardnum);
1302 if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL,
1303 card, 0, &snd_ctl_reg, name)) < 0)
1304 return err;
1305 return 0;
1306}
1307
1308/*
1309 * disconnection of the control device
1310 */
1311static int snd_ctl_dev_disconnect(snd_device_t *device)
1312{
1313 snd_card_t *card = device->device_data;
1314 struct list_head *flist;
1315 snd_ctl_file_t *ctl;
1316
1317 down_read(&card->controls_rwsem);
1318 list_for_each(flist, &card->ctl_files) {
1319 ctl = snd_ctl_file(flist);
1320 wake_up(&ctl->change_sleep);
1321 kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
1322 }
1323 up_read(&card->controls_rwsem);
1324 return 0;
1325}
1326
1327/*
1328 * free all controls
1329 */
1330static int snd_ctl_dev_free(snd_device_t *device)
1331{
1332 snd_card_t *card = device->device_data;
1333 snd_kcontrol_t *control;
1334
1335 down_write(&card->controls_rwsem);
1336 while (!list_empty(&card->controls)) {
1337 control = snd_kcontrol(card->controls.next);
1338 snd_ctl_remove(card, control);
1339 }
1340 up_write(&card->controls_rwsem);
1341 return 0;
1342}
1343
1344/*
1345 * de-registration of the control device
1346 */
1347static int snd_ctl_dev_unregister(snd_device_t *device)
1348{
1349 snd_card_t *card = device->device_data;
1350 int err, cardnum;
1351
1352 snd_assert(card != NULL, return -ENXIO);
1353 cardnum = card->number;
1354 snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
1355 if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, card, 0)) < 0)
1356 return err;
1357 return snd_ctl_dev_free(device);
1358}
1359
1360/*
1361 * create control core:
1362 * called from init.c
1363 */
1364int snd_ctl_create(snd_card_t *card)
1365{
1366 static snd_device_ops_t ops = {
1367 .dev_free = snd_ctl_dev_free,
1368 .dev_register = snd_ctl_dev_register,
1369 .dev_disconnect = snd_ctl_dev_disconnect,
1370 .dev_unregister = snd_ctl_dev_unregister
1371 };
1372
1373 snd_assert(card != NULL, return -ENXIO);
1374 return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
1375}
diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c
new file mode 100644
index 000000000000..7fdabea4bfc8
--- /dev/null
+++ b/sound/core/control_compat.c
@@ -0,0 +1,412 @@
1/*
2 * compat ioctls for control API
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
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/* this file included from control.c */
22
23#include <linux/compat.h>
24
25struct sndrv_ctl_elem_list32 {
26 u32 offset;
27 u32 space;
28 u32 used;
29 u32 count;
30 u32 pids;
31 unsigned char reserved[50];
32} /* don't set packed attribute here */;
33
34static int snd_ctl_elem_list_compat(snd_card_t *card, struct sndrv_ctl_elem_list32 __user *data32)
35{
36 struct sndrv_ctl_elem_list __user *data;
37 compat_caddr_t ptr;
38 int err;
39
40 data = compat_alloc_user_space(sizeof(*data));
41
42 /* offset, space, used, count */
43 if (copy_in_user(data, data32, 4 * sizeof(u32)))
44 return -EFAULT;
45 /* pids */
46 if (get_user(ptr, &data32->pids) ||
47 put_user(compat_ptr(ptr), &data->pids))
48 return -EFAULT;
49 err = snd_ctl_elem_list(card, data);
50 if (err < 0)
51 return err;
52 /* copy the result */
53 if (copy_in_user(data32, data, 4 * sizeof(u32)))
54 return -EFAULT;
55 return 0;
56}
57
58/*
59 * control element info
60 * it uses union, so the things are not easy..
61 */
62
63struct sndrv_ctl_elem_info32 {
64 struct sndrv_ctl_elem_id id; // the size of struct is same
65 s32 type;
66 u32 access;
67 u32 count;
68 s32 owner;
69 union {
70 struct {
71 s32 min;
72 s32 max;
73 s32 step;
74 } integer;
75 struct {
76 u64 min;
77 u64 max;
78 u64 step;
79 } integer64;
80 struct {
81 u32 items;
82 u32 item;
83 char name[64];
84 } enumerated;
85 unsigned char reserved[128];
86 } value;
87 unsigned char reserved[64];
88} __attribute__((packed));
89
90static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_info32 __user *data32)
91{
92 struct sndrv_ctl_elem_info *data;
93 int err;
94
95 data = kcalloc(1, sizeof(*data), GFP_KERNEL);
96 if (! data)
97 return -ENOMEM;
98
99 err = -EFAULT;
100 /* copy id */
101 if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
102 goto error;
103 /* we need to copy the item index.
104 * hope this doesn't break anything..
105 */
106 if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
107 goto error;
108 err = snd_ctl_elem_info(ctl, data);
109 if (err < 0)
110 goto error;
111 /* restore info to 32bit */
112 err = -EFAULT;
113 /* id, type, access, count */
114 if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
115 copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
116 goto error;
117 if (put_user(data->owner, &data32->owner))
118 goto error;
119 switch (data->type) {
120 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
121 case SNDRV_CTL_ELEM_TYPE_INTEGER:
122 if (put_user(data->value.integer.min, &data32->value.integer.min) ||
123 put_user(data->value.integer.max, &data32->value.integer.max) ||
124 put_user(data->value.integer.step, &data32->value.integer.step))
125 goto error;
126 break;
127 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
128 if (copy_to_user(&data32->value.integer64,
129 &data->value.integer64,
130 sizeof(data->value.integer64)))
131 goto error;
132 break;
133 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
134 if (copy_to_user(&data32->value.enumerated,
135 &data->value.enumerated,
136 sizeof(data->value.enumerated)))
137 goto error;
138 break;
139 default:
140 break;
141 }
142 err = 0;
143 error:
144 kfree(data);
145 return err;
146}
147
148/* read / write */
149struct sndrv_ctl_elem_value32 {
150 struct sndrv_ctl_elem_id id;
151 unsigned int indirect; /* bit-field causes misalignment */
152 union {
153 s32 integer[128];
154 unsigned char data[512];
155#ifndef CONFIG_X86_64
156 s64 integer64[64];
157#endif
158 } value;
159 unsigned char reserved[128];
160};
161
162
163/* get the value type and count of the control */
164static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id, int *countp)
165{
166 snd_kcontrol_t *kctl;
167 snd_ctl_elem_info_t info;
168 int err;
169
170 down_read(&card->controls_rwsem);
171 kctl = snd_ctl_find_id(card, id);
172 if (! kctl) {
173 up_read(&card->controls_rwsem);
174 return -ENXIO;
175 }
176 info.id = *id;
177 err = kctl->info(kctl, &info);
178 up_read(&card->controls_rwsem);
179 if (err >= 0) {
180 err = info.type;
181 *countp = info.count;
182 }
183 return err;
184}
185
186static int get_elem_size(int type, int count)
187{
188 switch (type) {
189 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
190 return sizeof(s64) * count;
191 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
192 return sizeof(int) * count;
193 case SNDRV_CTL_ELEM_TYPE_BYTES:
194 return 512;
195 case SNDRV_CTL_ELEM_TYPE_IEC958:
196 return sizeof(struct sndrv_aes_iec958);
197 default:
198 return -1;
199 }
200}
201
202static int copy_ctl_value_from_user(snd_card_t *card,
203 struct sndrv_ctl_elem_value *data,
204 struct sndrv_ctl_elem_value32 __user *data32,
205 int *typep, int *countp)
206{
207 int i, type, count, size;
208 unsigned int indirect;
209
210 if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
211 return -EFAULT;
212 if (get_user(indirect, &data32->indirect))
213 return -EFAULT;
214 if (indirect)
215 return -EINVAL;
216 type = get_ctl_type(card, &data->id, &count);
217 if (type < 0)
218 return type;
219
220 if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
221 type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
222 for (i = 0; i < count; i++) {
223 int val;
224 if (get_user(val, &data32->value.integer[i]))
225 return -EFAULT;
226 data->value.integer.value[i] = val;
227 }
228 } else {
229 size = get_elem_size(type, count);
230 if (size < 0) {
231 printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
232 return -EINVAL;
233 }
234 if (copy_from_user(data->value.bytes.data,
235 data32->value.data, size))
236 return -EFAULT;
237 }
238
239 *typep = type;
240 *countp = count;
241 return 0;
242}
243
244/* restore the value to 32bit */
245static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user *data32,
246 struct sndrv_ctl_elem_value *data,
247 int type, int count)
248{
249 int i, size;
250
251 if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
252 type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
253 for (i = 0; i < count; i++) {
254 int val;
255 val = data->value.integer.value[i];
256 if (put_user(val, &data32->value.integer[i]))
257 return -EFAULT;
258 }
259 } else {
260 size = get_elem_size(type, count);
261 if (copy_to_user(data32->value.data,
262 data->value.bytes.data, size))
263 return -EFAULT;
264 }
265 return 0;
266}
267
268static int snd_ctl_elem_read_user_compat(snd_card_t *card,
269 struct sndrv_ctl_elem_value32 __user *data32)
270{
271 struct sndrv_ctl_elem_value *data;
272 int err, type, count;
273
274 data = kcalloc(1, sizeof(*data), GFP_KERNEL);
275 if (data == NULL)
276 return -ENOMEM;
277
278 if ((err = copy_ctl_value_from_user(card, data, data32, &type, &count)) < 0)
279 goto error;
280 if ((err = snd_ctl_elem_read(card, data)) < 0)
281 goto error;
282 err = copy_ctl_value_to_user(data32, data, type, count);
283 error:
284 kfree(data);
285 return err;
286}
287
288static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file,
289 struct sndrv_ctl_elem_value32 __user *data32)
290{
291 struct sndrv_ctl_elem_value *data;
292 int err, type, count;
293
294 data = kcalloc(1, sizeof(*data), GFP_KERNEL);
295 if (data == NULL)
296 return -ENOMEM;
297
298 if ((err = copy_ctl_value_from_user(file->card, data, data32, &type, &count)) < 0)
299 goto error;
300 if ((err = snd_ctl_elem_write(file->card, file, data)) < 0)
301 goto error;
302 err = copy_ctl_value_to_user(data32, data, type, count);
303 error:
304 kfree(data);
305 return err;
306}
307
308/* add or replace a user control */
309static int snd_ctl_elem_add_compat(snd_ctl_file_t *file,
310 struct sndrv_ctl_elem_info32 __user *data32,
311 int replace)
312{
313 struct sndrv_ctl_elem_info *data;
314 int err;
315
316 data = kcalloc(1, sizeof(*data), GFP_KERNEL);
317 if (! data)
318 return -ENOMEM;
319
320 err = -EFAULT;
321 /* id, type, access, count */ \
322 if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
323 copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
324 goto error;
325 if (get_user(data->owner, &data32->owner) ||
326 get_user(data->type, &data32->type))
327 goto error;
328 switch (data->type) {
329 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
330 case SNDRV_CTL_ELEM_TYPE_INTEGER:
331 if (get_user(data->value.integer.min, &data32->value.integer.min) ||
332 get_user(data->value.integer.max, &data32->value.integer.max) ||
333 get_user(data->value.integer.step, &data32->value.integer.step))
334 goto error;
335 break;
336 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
337 if (copy_from_user(&data->value.integer64,
338 &data32->value.integer64,
339 sizeof(data->value.integer64)))
340 goto error;
341 break;
342 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
343 if (copy_from_user(&data->value.enumerated,
344 &data32->value.enumerated,
345 sizeof(data->value.enumerated)))
346 goto error;
347 break;
348 default:
349 break;
350 }
351 err = snd_ctl_elem_add(file, data, replace);
352 error:
353 kfree(data);
354 return err;
355}
356
357enum {
358 SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
359 SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
360 SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
361 SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
362 SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct sndrv_ctl_elem_info32),
363 SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct sndrv_ctl_elem_info32),
364};
365
366static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
367{
368 snd_ctl_file_t *ctl;
369 struct list_head *list;
370 void __user *argp = compat_ptr(arg);
371 int err;
372
373 ctl = file->private_data;
374 snd_assert(ctl && ctl->card, return -ENXIO);
375
376 switch (cmd) {
377 case SNDRV_CTL_IOCTL_PVERSION:
378 case SNDRV_CTL_IOCTL_CARD_INFO:
379 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
380 case SNDRV_CTL_IOCTL_POWER:
381 case SNDRV_CTL_IOCTL_POWER_STATE:
382 case SNDRV_CTL_IOCTL_ELEM_LOCK:
383 case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
384 return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
385 case SNDRV_CTL_IOCTL_ELEM_LIST32:
386 return snd_ctl_elem_list_compat(ctl->card, argp);
387 case SNDRV_CTL_IOCTL_ELEM_INFO32:
388 return snd_ctl_elem_info_compat(ctl, argp);
389 case SNDRV_CTL_IOCTL_ELEM_READ32:
390 return snd_ctl_elem_read_user_compat(ctl->card, argp);
391 case SNDRV_CTL_IOCTL_ELEM_WRITE32:
392 return snd_ctl_elem_write_user_compat(ctl, argp);
393 case SNDRV_CTL_IOCTL_ELEM_ADD32:
394 return snd_ctl_elem_add_compat(ctl, argp, 0);
395 case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
396 return snd_ctl_elem_add_compat(ctl, argp, 1);
397 }
398
399 down_read(&snd_ioctl_rwsem);
400 list_for_each(list, &snd_control_compat_ioctls) {
401 snd_kctl_ioctl_t *p = list_entry(list, snd_kctl_ioctl_t, list);
402 if (p->fioctl) {
403 err = p->fioctl(ctl->card, ctl, cmd, arg);
404 if (err != -ENOIOCTLCMD) {
405 up_read(&snd_ioctl_rwsem);
406 return err;
407 }
408 }
409 }
410 up_read(&snd_ioctl_rwsem);
411 return -ENOIOCTLCMD;
412}
diff --git a/sound/core/device.c b/sound/core/device.c
new file mode 100644
index 000000000000..18c71f913d2a
--- /dev/null
+++ b/sound/core/device.c
@@ -0,0 +1,240 @@
1/*
2 * Device management routines
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/slab.h>
24#include <linux/time.h>
25#include <linux/errno.h>
26#include <sound/core.h>
27
28/**
29 * snd_device_new - create an ALSA device component
30 * @card: the card instance
31 * @type: the device type, SNDRV_DEV_TYPE_XXX
32 * @device_data: the data pointer of this device
33 * @ops: the operator table
34 *
35 * Creates a new device component for the given data pointer.
36 * The device will be assigned to the card and managed together
37 * by the card.
38 *
39 * The data pointer plays a role as the identifier, too, so the
40 * pointer address must be unique and unchanged.
41 *
42 * Returns zero if successful, or a negative error code on failure.
43 */
44int snd_device_new(snd_card_t *card, snd_device_type_t type,
45 void *device_data, snd_device_ops_t *ops)
46{
47 snd_device_t *dev;
48
49 snd_assert(card != NULL && device_data != NULL && ops != NULL, return -ENXIO);
50 dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
51 if (dev == NULL)
52 return -ENOMEM;
53 dev->card = card;
54 dev->type = type;
55 dev->state = SNDRV_DEV_BUILD;
56 dev->device_data = device_data;
57 dev->ops = ops;
58 list_add(&dev->list, &card->devices); /* add to the head of list */
59 return 0;
60}
61
62/**
63 * snd_device_free - release the device from the card
64 * @card: the card instance
65 * @device_data: the data pointer to release
66 *
67 * Removes the device from the list on the card and invokes the
68 * callback, dev_unregister or dev_free, corresponding to the state.
69 * Then release the device.
70 *
71 * Returns zero if successful, or a negative error code on failure or if the
72 * device not found.
73 */
74int snd_device_free(snd_card_t *card, void *device_data)
75{
76 struct list_head *list;
77 snd_device_t *dev;
78
79 snd_assert(card != NULL, return -ENXIO);
80 snd_assert(device_data != NULL, return -ENXIO);
81 list_for_each(list, &card->devices) {
82 dev = snd_device(list);
83 if (dev->device_data != device_data)
84 continue;
85 /* unlink */
86 list_del(&dev->list);
87 if ((dev->state == SNDRV_DEV_REGISTERED || dev->state == SNDRV_DEV_DISCONNECTED) &&
88 dev->ops->dev_unregister) {
89 if (dev->ops->dev_unregister(dev))
90 snd_printk(KERN_ERR "device unregister failure\n");
91 } else {
92 if (dev->ops->dev_free) {
93 if (dev->ops->dev_free(dev))
94 snd_printk(KERN_ERR "device free failure\n");
95 }
96 }
97 kfree(dev);
98 return 0;
99 }
100 snd_printd("device free %p (from %p), not found\n", device_data, __builtin_return_address(0));
101 return -ENXIO;
102}
103
104/**
105 * snd_device_free - disconnect the device
106 * @card: the card instance
107 * @device_data: the data pointer to disconnect
108 *
109 * Turns the device into the disconnection state, invoking
110 * dev_disconnect callback, if the device was already registered.
111 *
112 * Usually called from snd_card_disconnect().
113 *
114 * Returns zero if successful, or a negative error code on failure or if the
115 * device not found.
116 */
117int snd_device_disconnect(snd_card_t *card, void *device_data)
118{
119 struct list_head *list;
120 snd_device_t *dev;
121
122 snd_assert(card != NULL, return -ENXIO);
123 snd_assert(device_data != NULL, return -ENXIO);
124 list_for_each(list, &card->devices) {
125 dev = snd_device(list);
126 if (dev->device_data != device_data)
127 continue;
128 if (dev->state == SNDRV_DEV_REGISTERED && dev->ops->dev_disconnect) {
129 if (dev->ops->dev_disconnect(dev))
130 snd_printk(KERN_ERR "device disconnect failure\n");
131 dev->state = SNDRV_DEV_DISCONNECTED;
132 }
133 return 0;
134 }
135 snd_printd("device disconnect %p (from %p), not found\n", device_data, __builtin_return_address(0));
136 return -ENXIO;
137}
138
139/**
140 * snd_device_register - register the device
141 * @card: the card instance
142 * @device_data: the data pointer to register
143 *
144 * Registers the device which was already created via
145 * snd_device_new(). Usually this is called from snd_card_register(),
146 * but it can be called later if any new devices are created after
147 * invocation of snd_card_register().
148 *
149 * Returns zero if successful, or a negative error code on failure or if the
150 * device not found.
151 */
152int snd_device_register(snd_card_t *card, void *device_data)
153{
154 struct list_head *list;
155 snd_device_t *dev;
156 int err;
157
158 snd_assert(card != NULL && device_data != NULL, return -ENXIO);
159 list_for_each(list, &card->devices) {
160 dev = snd_device(list);
161 if (dev->device_data != device_data)
162 continue;
163 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
164 if ((err = dev->ops->dev_register(dev)) < 0)
165 return err;
166 dev->state = SNDRV_DEV_REGISTERED;
167 return 0;
168 }
169 return -EBUSY;
170 }
171 snd_BUG();
172 return -ENXIO;
173}
174
175/*
176 * register all the devices on the card.
177 * called from init.c
178 */
179int snd_device_register_all(snd_card_t *card)
180{
181 struct list_head *list;
182 snd_device_t *dev;
183 int err;
184
185 snd_assert(card != NULL, return -ENXIO);
186 list_for_each(list, &card->devices) {
187 dev = snd_device(list);
188 if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
189 if ((err = dev->ops->dev_register(dev)) < 0)
190 return err;
191 dev->state = SNDRV_DEV_REGISTERED;
192 }
193 }
194 return 0;
195}
196
197/*
198 * disconnect all the devices on the card.
199 * called from init.c
200 */
201int snd_device_disconnect_all(snd_card_t *card)
202{
203 snd_device_t *dev;
204 struct list_head *list;
205 int err = 0;
206
207 snd_assert(card != NULL, return -ENXIO);
208 list_for_each(list, &card->devices) {
209 dev = snd_device(list);
210 if (snd_device_disconnect(card, dev->device_data) < 0)
211 err = -ENXIO;
212 }
213 return err;
214}
215
216/*
217 * release all the devices on the card.
218 * called from init.c
219 */
220int snd_device_free_all(snd_card_t *card, snd_device_cmd_t cmd)
221{
222 snd_device_t *dev;
223 struct list_head *list;
224 int err;
225 unsigned int range_low, range_high;
226
227 snd_assert(card != NULL, return -ENXIO);
228 range_low = cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
229 range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
230 __again:
231 list_for_each(list, &card->devices) {
232 dev = snd_device(list);
233 if (dev->type >= range_low && dev->type <= range_high) {
234 if ((err = snd_device_free(card, dev->device_data)) < 0)
235 return err;
236 goto __again;
237 }
238 }
239 return 0;
240}
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
new file mode 100644
index 000000000000..997dd41c584e
--- /dev/null
+++ b/sound/core/hwdep.c
@@ -0,0 +1,524 @@
1/*
2 * Hardware dependent layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/major.h>
24#include <linux/init.h>
25#include <linux/smp_lock.h>
26#include <linux/slab.h>
27#include <linux/time.h>
28#include <sound/core.h>
29#include <sound/control.h>
30#include <sound/minors.h>
31#include <sound/hwdep.h>
32#include <sound/info.h>
33
34MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
35MODULE_DESCRIPTION("Hardware dependent layer");
36MODULE_LICENSE("GPL");
37
38static snd_hwdep_t *snd_hwdep_devices[SNDRV_CARDS * SNDRV_MINOR_HWDEPS];
39
40static DECLARE_MUTEX(register_mutex);
41
42static int snd_hwdep_free(snd_hwdep_t *hwdep);
43static int snd_hwdep_dev_free(snd_device_t *device);
44static int snd_hwdep_dev_register(snd_device_t *device);
45static int snd_hwdep_dev_unregister(snd_device_t *device);
46
47/*
48
49 */
50
51static loff_t snd_hwdep_llseek(struct file * file, loff_t offset, int orig)
52{
53 snd_hwdep_t *hw = file->private_data;
54 if (hw->ops.llseek)
55 return hw->ops.llseek(hw, file, offset, orig);
56 return -ENXIO;
57}
58
59static ssize_t snd_hwdep_read(struct file * file, char __user *buf, size_t count, loff_t *offset)
60{
61 snd_hwdep_t *hw = file->private_data;
62 if (hw->ops.read)
63 return hw->ops.read(hw, buf, count, offset);
64 return -ENXIO;
65}
66
67static ssize_t snd_hwdep_write(struct file * file, const char __user *buf, size_t count, loff_t *offset)
68{
69 snd_hwdep_t *hw = file->private_data;
70 if (hw->ops.write)
71 return hw->ops.write(hw, buf, count, offset);
72 return -ENXIO;
73}
74
75static int snd_hwdep_open(struct inode *inode, struct file * file)
76{
77 int major = imajor(inode);
78 int cardnum;
79 int device;
80 snd_hwdep_t *hw;
81 int err;
82 wait_queue_t wait;
83
84 switch (major) {
85 case CONFIG_SND_MAJOR:
86 cardnum = SNDRV_MINOR_CARD(iminor(inode));
87 device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_HWDEP;
88 break;
89#ifdef CONFIG_SND_OSSEMUL
90 case SOUND_MAJOR:
91 cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
92 device = 0;
93 break;
94#endif
95 default:
96 return -ENXIO;
97 }
98 cardnum %= SNDRV_CARDS;
99 device %= SNDRV_MINOR_HWDEPS;
100 hw = snd_hwdep_devices[(cardnum * SNDRV_MINOR_HWDEPS) + device];
101 if (hw == NULL)
102 return -ENODEV;
103
104 if (!hw->ops.open)
105 return -ENXIO;
106#ifdef CONFIG_SND_OSSEMUL
107 if (major == SOUND_MAJOR && hw->oss_type < 0)
108 return -ENXIO;
109#endif
110
111 if (!try_module_get(hw->card->module))
112 return -EFAULT;
113
114 init_waitqueue_entry(&wait, current);
115 add_wait_queue(&hw->open_wait, &wait);
116 down(&hw->open_mutex);
117 while (1) {
118 if (hw->exclusive && hw->used > 0) {
119 err = -EBUSY;
120 break;
121 }
122 err = hw->ops.open(hw, file);
123 if (err >= 0)
124 break;
125 if (err == -EAGAIN) {
126 if (file->f_flags & O_NONBLOCK) {
127 err = -EBUSY;
128 break;
129 }
130 } else
131 break;
132 set_current_state(TASK_INTERRUPTIBLE);
133 up(&hw->open_mutex);
134 schedule();
135 down(&hw->open_mutex);
136 if (signal_pending(current)) {
137 err = -ERESTARTSYS;
138 break;
139 }
140 }
141 remove_wait_queue(&hw->open_wait, &wait);
142 if (err >= 0) {
143 err = snd_card_file_add(hw->card, file);
144 if (err >= 0) {
145 file->private_data = hw;
146 hw->used++;
147 } else {
148 if (hw->ops.release)
149 hw->ops.release(hw, file);
150 }
151 }
152 up(&hw->open_mutex);
153 if (err < 0)
154 module_put(hw->card->module);
155 return err;
156}
157
158static int snd_hwdep_release(struct inode *inode, struct file * file)
159{
160 int err = -ENXIO;
161 snd_hwdep_t *hw = file->private_data;
162 down(&hw->open_mutex);
163 if (hw->ops.release) {
164 err = hw->ops.release(hw, file);
165 wake_up(&hw->open_wait);
166 }
167 if (hw->used > 0)
168 hw->used--;
169 snd_card_file_remove(hw->card, file);
170 up(&hw->open_mutex);
171 module_put(hw->card->module);
172 return err;
173}
174
175static unsigned int snd_hwdep_poll(struct file * file, poll_table * wait)
176{
177 snd_hwdep_t *hw = file->private_data;
178 if (hw->ops.poll)
179 return hw->ops.poll(hw, file, wait);
180 return 0;
181}
182
183static int snd_hwdep_info(snd_hwdep_t *hw, snd_hwdep_info_t __user *_info)
184{
185 snd_hwdep_info_t info;
186
187 memset(&info, 0, sizeof(info));
188 info.card = hw->card->number;
189 strlcpy(info.id, hw->id, sizeof(info.id));
190 strlcpy(info.name, hw->name, sizeof(info.name));
191 info.iface = hw->iface;
192 if (copy_to_user(_info, &info, sizeof(info)))
193 return -EFAULT;
194 return 0;
195}
196
197static int snd_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t __user *_info)
198{
199 snd_hwdep_dsp_status_t info;
200 int err;
201
202 if (! hw->ops.dsp_status)
203 return -ENXIO;
204 memset(&info, 0, sizeof(info));
205 info.dsp_loaded = hw->dsp_loaded;
206 if ((err = hw->ops.dsp_status(hw, &info)) < 0)
207 return err;
208 if (copy_to_user(_info, &info, sizeof(info)))
209 return -EFAULT;
210 return 0;
211}
212
213static int snd_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t __user *_info)
214{
215 snd_hwdep_dsp_image_t info;
216 int err;
217
218 if (! hw->ops.dsp_load)
219 return -ENXIO;
220 memset(&info, 0, sizeof(info));
221 if (copy_from_user(&info, _info, sizeof(info)))
222 return -EFAULT;
223 /* check whether the dsp was already loaded */
224 if (hw->dsp_loaded & (1 << info.index))
225 return -EBUSY;
226 if (!access_ok(VERIFY_READ, info.image, info.length))
227 return -EFAULT;
228 err = hw->ops.dsp_load(hw, &info);
229 if (err < 0)
230 return err;
231 hw->dsp_loaded |= (1 << info.index);
232 return 0;
233}
234
235static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
236{
237 snd_hwdep_t *hw = file->private_data;
238 void __user *argp = (void __user *)arg;
239 switch (cmd) {
240 case SNDRV_HWDEP_IOCTL_PVERSION:
241 return put_user(SNDRV_HWDEP_VERSION, (int __user *)argp);
242 case SNDRV_HWDEP_IOCTL_INFO:
243 return snd_hwdep_info(hw, argp);
244 case SNDRV_HWDEP_IOCTL_DSP_STATUS:
245 return snd_hwdep_dsp_status(hw, argp);
246 case SNDRV_HWDEP_IOCTL_DSP_LOAD:
247 return snd_hwdep_dsp_load(hw, argp);
248 }
249 if (hw->ops.ioctl)
250 return hw->ops.ioctl(hw, file, cmd, arg);
251 return -ENOTTY;
252}
253
254static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
255{
256 snd_hwdep_t *hw = file->private_data;
257 if (hw->ops.mmap)
258 return hw->ops.mmap(hw, file, vma);
259 return -ENXIO;
260}
261
262static int snd_hwdep_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
263 unsigned int cmd, unsigned long arg)
264{
265 unsigned int tmp;
266
267 tmp = card->number * SNDRV_MINOR_HWDEPS;
268 switch (cmd) {
269 case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE:
270 {
271 int device;
272
273 if (get_user(device, (int __user *)arg))
274 return -EFAULT;
275 device = device < 0 ? 0 : device + 1;
276 while (device < SNDRV_MINOR_HWDEPS) {
277 if (snd_hwdep_devices[tmp + device])
278 break;
279 device++;
280 }
281 if (device >= SNDRV_MINOR_HWDEPS)
282 device = -1;
283 if (put_user(device, (int __user *)arg))
284 return -EFAULT;
285 return 0;
286 }
287 case SNDRV_CTL_IOCTL_HWDEP_INFO:
288 {
289 snd_hwdep_info_t __user *info = (snd_hwdep_info_t __user *)arg;
290 int device;
291 snd_hwdep_t *hwdep;
292
293 if (get_user(device, &info->device))
294 return -EFAULT;
295 if (device < 0 || device >= SNDRV_MINOR_HWDEPS)
296 return -ENXIO;
297 hwdep = snd_hwdep_devices[tmp + device];
298 if (hwdep == NULL)
299 return -ENXIO;
300 return snd_hwdep_info(hwdep, info);
301 }
302 }
303 return -ENOIOCTLCMD;
304}
305
306#ifdef CONFIG_COMPAT
307#include "hwdep_compat.c"
308#else
309#define snd_hwdep_ioctl_compat NULL
310#endif
311
312/*
313
314 */
315
316static struct file_operations snd_hwdep_f_ops =
317{
318 .owner = THIS_MODULE,
319 .llseek = snd_hwdep_llseek,
320 .read = snd_hwdep_read,
321 .write = snd_hwdep_write,
322 .open = snd_hwdep_open,
323 .release = snd_hwdep_release,
324 .poll = snd_hwdep_poll,
325 .unlocked_ioctl = snd_hwdep_ioctl,
326 .compat_ioctl = snd_hwdep_ioctl_compat,
327 .mmap = snd_hwdep_mmap,
328};
329
330static snd_minor_t snd_hwdep_reg =
331{
332 .comment = "hardware dependent",
333 .f_ops = &snd_hwdep_f_ops,
334};
335
336/**
337 * snd_hwdep_new - create a new hwdep instance
338 * @card: the card instance
339 * @id: the id string
340 * @device: the device index (zero-based)
341 * @rhwdep: the pointer to store the new hwdep instance
342 *
343 * Creates a new hwdep instance with the given index on the card.
344 * The callbacks (hwdep->ops) must be set on the returned instance
345 * after this call manually by the caller.
346 *
347 * Returns zero if successful, or a negative error code on failure.
348 */
349int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep)
350{
351 snd_hwdep_t *hwdep;
352 int err;
353 static snd_device_ops_t ops = {
354 .dev_free = snd_hwdep_dev_free,
355 .dev_register = snd_hwdep_dev_register,
356 .dev_unregister = snd_hwdep_dev_unregister
357 };
358
359 snd_assert(rhwdep != NULL, return -EINVAL);
360 *rhwdep = NULL;
361 snd_assert(card != NULL, return -ENXIO);
362 hwdep = kcalloc(1, sizeof(*hwdep), GFP_KERNEL);
363 if (hwdep == NULL)
364 return -ENOMEM;
365 hwdep->card = card;
366 hwdep->device = device;
367 if (id) {
368 strlcpy(hwdep->id, id, sizeof(hwdep->id));
369 }
370#ifdef CONFIG_SND_OSSEMUL
371 hwdep->oss_type = -1;
372#endif
373 if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) {
374 snd_hwdep_free(hwdep);
375 return err;
376 }
377 init_waitqueue_head(&hwdep->open_wait);
378 init_MUTEX(&hwdep->open_mutex);
379 *rhwdep = hwdep;
380 return 0;
381}
382
383static int snd_hwdep_free(snd_hwdep_t *hwdep)
384{
385 snd_assert(hwdep != NULL, return -ENXIO);
386 if (hwdep->private_free)
387 hwdep->private_free(hwdep);
388 kfree(hwdep);
389 return 0;
390}
391
392static int snd_hwdep_dev_free(snd_device_t *device)
393{
394 snd_hwdep_t *hwdep = device->device_data;
395 return snd_hwdep_free(hwdep);
396}
397
398static int snd_hwdep_dev_register(snd_device_t *device)
399{
400 snd_hwdep_t *hwdep = device->device_data;
401 int idx, err;
402 char name[32];
403
404 down(&register_mutex);
405 idx = (hwdep->card->number * SNDRV_MINOR_HWDEPS) + hwdep->device;
406 if (snd_hwdep_devices[idx]) {
407 up(&register_mutex);
408 return -EBUSY;
409 }
410 snd_hwdep_devices[idx] = hwdep;
411 sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device);
412 if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
413 hwdep->card, hwdep->device,
414 &snd_hwdep_reg, name)) < 0) {
415 snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n",
416 hwdep->card->number, hwdep->device);
417 snd_hwdep_devices[idx] = NULL;
418 up(&register_mutex);
419 return err;
420 }
421#ifdef CONFIG_SND_OSSEMUL
422 hwdep->ossreg = 0;
423 if (hwdep->oss_type >= 0) {
424 if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) {
425 snd_printk (KERN_WARNING "only hwdep device 0 can be registered as OSS direct FM device!\n");
426 } else {
427 if (snd_register_oss_device(hwdep->oss_type,
428 hwdep->card, hwdep->device,
429 &snd_hwdep_reg, hwdep->oss_dev) < 0) {
430 snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n",
431 hwdep->card->number, hwdep->device);
432 } else
433 hwdep->ossreg = 1;
434 }
435 }
436#endif
437 up(&register_mutex);
438 return 0;
439}
440
441static int snd_hwdep_dev_unregister(snd_device_t *device)
442{
443 snd_hwdep_t *hwdep = device->device_data;
444 int idx;
445
446 snd_assert(hwdep != NULL, return -ENXIO);
447 down(&register_mutex);
448 idx = (hwdep->card->number * SNDRV_MINOR_HWDEPS) + hwdep->device;
449 if (snd_hwdep_devices[idx] != hwdep) {
450 up(&register_mutex);
451 return -EINVAL;
452 }
453#ifdef CONFIG_SND_OSSEMUL
454 if (hwdep->ossreg)
455 snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
456#endif
457 snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
458 snd_hwdep_devices[idx] = NULL;
459 up(&register_mutex);
460 return snd_hwdep_free(hwdep);
461}
462
463/*
464 * Info interface
465 */
466
467static void snd_hwdep_proc_read(snd_info_entry_t *entry,
468 snd_info_buffer_t * buffer)
469{
470 int idx;
471 snd_hwdep_t *hwdep;
472
473 down(&register_mutex);
474 for (idx = 0; idx < SNDRV_CARDS * SNDRV_MINOR_HWDEPS; idx++) {
475 hwdep = snd_hwdep_devices[idx];
476 if (hwdep == NULL)
477 continue;
478 snd_iprintf(buffer, "%02i-%02i: %s\n",
479 idx / SNDRV_MINOR_HWDEPS,
480 idx % SNDRV_MINOR_HWDEPS,
481 hwdep->name);
482 }
483 up(&register_mutex);
484}
485
486/*
487 * ENTRY functions
488 */
489
490static snd_info_entry_t *snd_hwdep_proc_entry = NULL;
491
492static int __init alsa_hwdep_init(void)
493{
494 snd_info_entry_t *entry;
495
496 memset(snd_hwdep_devices, 0, sizeof(snd_hwdep_devices));
497 if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) {
498 entry->c.text.read_size = 512;
499 entry->c.text.read = snd_hwdep_proc_read;
500 if (snd_info_register(entry) < 0) {
501 snd_info_free_entry(entry);
502 entry = NULL;
503 }
504 }
505 snd_hwdep_proc_entry = entry;
506 snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
507 snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
508 return 0;
509}
510
511static void __exit alsa_hwdep_exit(void)
512{
513 snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
514 snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
515 if (snd_hwdep_proc_entry) {
516 snd_info_unregister(snd_hwdep_proc_entry);
517 snd_hwdep_proc_entry = NULL;
518 }
519}
520
521module_init(alsa_hwdep_init)
522module_exit(alsa_hwdep_exit)
523
524EXPORT_SYMBOL(snd_hwdep_new);
diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c
new file mode 100644
index 000000000000..6866f423d4b9
--- /dev/null
+++ b/sound/core/hwdep_compat.c
@@ -0,0 +1,77 @@
1/*
2 * 32bit -> 64bit ioctl wrapper for hwdep API
3 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21/* This file is included from hwdep.c */
22
23#include <linux/compat.h>
24
25struct sndrv_hwdep_dsp_image32 {
26 u32 index;
27 unsigned char name[64];
28 u32 image; /* pointer */
29 u32 length;
30 u32 driver_data;
31} /* don't set packed attribute here */;
32
33static int snd_hwdep_dsp_load_compat(snd_hwdep_t *hw,
34 struct sndrv_hwdep_dsp_image32 __user *src)
35{
36 struct sndrv_hwdep_dsp_image *dst;
37 compat_caddr_t ptr;
38 u32 val;
39
40 dst = compat_alloc_user_space(sizeof(*dst));
41
42 /* index and name */
43 if (copy_in_user(dst, src, 4 + 64))
44 return -EFAULT;
45 if (get_user(ptr, &src->image) ||
46 put_user(compat_ptr(ptr), &dst->image))
47 return -EFAULT;
48 if (get_user(val, &src->length) ||
49 put_user(val, &dst->length))
50 return -EFAULT;
51 if (get_user(val, &src->driver_data) ||
52 put_user(val, &dst->driver_data))
53 return -EFAULT;
54
55 return snd_hwdep_dsp_load(hw, dst);
56}
57
58enum {
59 SNDRV_HWDEP_IOCTL_DSP_LOAD32 = _IOW('H', 0x03, struct sndrv_hwdep_dsp_image32)
60};
61
62static long snd_hwdep_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg)
63{
64 snd_hwdep_t *hw = file->private_data;
65 void __user *argp = compat_ptr(arg);
66 switch (cmd) {
67 case SNDRV_HWDEP_IOCTL_PVERSION:
68 case SNDRV_HWDEP_IOCTL_INFO:
69 case SNDRV_HWDEP_IOCTL_DSP_STATUS:
70 return snd_hwdep_ioctl(file, cmd, (unsigned long)argp);
71 case SNDRV_HWDEP_IOCTL_DSP_LOAD32:
72 return snd_hwdep_dsp_load_compat(hw, argp);
73 }
74 if (hw->ops.ioctl_compat)
75 return hw->ops.ioctl_compat(hw, file, cmd, arg);
76 return -ENOIOCTLCMD;
77}
diff --git a/sound/core/info.c b/sound/core/info.c
new file mode 100644
index 000000000000..31faffe01cb0
--- /dev/null
+++ b/sound/core/info.c
@@ -0,0 +1,989 @@
1/*
2 * Information interface for ALSA driver
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/vmalloc.h>
25#include <linux/time.h>
26#include <linux/smp_lock.h>
27#include <sound/core.h>
28#include <sound/minors.h>
29#include <sound/info.h>
30#include <sound/version.h>
31#include <linux/proc_fs.h>
32#include <linux/devfs_fs_kernel.h>
33#include <stdarg.h>
34
35/*
36 *
37 */
38
39int snd_info_check_reserved_words(const char *str)
40{
41 static char *reserved[] =
42 {
43 "version",
44 "meminfo",
45 "memdebug",
46 "detect",
47 "devices",
48 "oss",
49 "cards",
50 "timers",
51 "synth",
52 "pcm",
53 "seq",
54 NULL
55 };
56 char **xstr = reserved;
57
58 while (*xstr) {
59 if (!strcmp(*xstr, str))
60 return 0;
61 xstr++;
62 }
63 if (!strncmp(str, "card", 4))
64 return 0;
65 return 1;
66}
67
68#ifdef CONFIG_PROC_FS
69
70static DECLARE_MUTEX(info_mutex);
71
72typedef struct _snd_info_private_data {
73 snd_info_buffer_t *rbuffer;
74 snd_info_buffer_t *wbuffer;
75 snd_info_entry_t *entry;
76 void *file_private_data;
77} snd_info_private_data_t;
78
79static int snd_info_version_init(void);
80static int snd_info_version_done(void);
81
82
83/**
84 * snd_iprintf - printf on the procfs buffer
85 * @buffer: the procfs buffer
86 * @fmt: the printf format
87 *
88 * Outputs the string on the procfs buffer just like printf().
89 *
90 * Returns the size of output string.
91 */
92int snd_iprintf(snd_info_buffer_t * buffer, char *fmt,...)
93{
94 va_list args;
95 int len, res;
96
97 if (buffer->stop || buffer->error)
98 return 0;
99 len = buffer->len - buffer->size;
100 va_start(args, fmt);
101 res = vsnprintf(buffer->curr, len, fmt, args);
102 va_end(args);
103 if (res >= len) {
104 buffer->stop = 1;
105 return 0;
106 }
107 buffer->curr += res;
108 buffer->size += res;
109 return res;
110}
111
112/*
113
114 */
115
116static struct proc_dir_entry *snd_proc_root = NULL;
117snd_info_entry_t *snd_seq_root = NULL;
118#ifdef CONFIG_SND_OSSEMUL
119snd_info_entry_t *snd_oss_root = NULL;
120#endif
121
122static inline void snd_info_entry_prepare(struct proc_dir_entry *de)
123{
124 de->owner = THIS_MODULE;
125}
126
127static void snd_remove_proc_entry(struct proc_dir_entry *parent,
128 struct proc_dir_entry *de)
129{
130 if (de)
131 remove_proc_entry(de->name, parent);
132}
133
134static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
135{
136 snd_info_private_data_t *data;
137 struct snd_info_entry *entry;
138 loff_t ret;
139
140 data = file->private_data;
141 entry = data->entry;
142 lock_kernel();
143 switch (entry->content) {
144 case SNDRV_INFO_CONTENT_TEXT:
145 switch (orig) {
146 case 0: /* SEEK_SET */
147 file->f_pos = offset;
148 ret = file->f_pos;
149 goto out;
150 case 1: /* SEEK_CUR */
151 file->f_pos += offset;
152 ret = file->f_pos;
153 goto out;
154 case 2: /* SEEK_END */
155 default:
156 ret = -EINVAL;
157 goto out;
158 }
159 break;
160 case SNDRV_INFO_CONTENT_DATA:
161 if (entry->c.ops->llseek) {
162 ret = entry->c.ops->llseek(entry,
163 data->file_private_data,
164 file, offset, orig);
165 goto out;
166 }
167 break;
168 }
169 ret = -ENXIO;
170out:
171 unlock_kernel();
172 return ret;
173}
174
175static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
176 size_t count, loff_t * offset)
177{
178 snd_info_private_data_t *data;
179 struct snd_info_entry *entry;
180 snd_info_buffer_t *buf;
181 size_t size = 0;
182 loff_t pos;
183
184 data = file->private_data;
185 snd_assert(data != NULL, return -ENXIO);
186 pos = *offset;
187 if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
188 return -EIO;
189 if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
190 return -EIO;
191 entry = data->entry;
192 switch (entry->content) {
193 case SNDRV_INFO_CONTENT_TEXT:
194 buf = data->rbuffer;
195 if (buf == NULL)
196 return -EIO;
197 if (pos >= buf->size)
198 return 0;
199 size = buf->size - pos;
200 size = min(count, size);
201 if (copy_to_user(buffer, buf->buffer + pos, size))
202 return -EFAULT;
203 break;
204 case SNDRV_INFO_CONTENT_DATA:
205 if (entry->c.ops->read)
206 size = entry->c.ops->read(entry,
207 data->file_private_data,
208 file, buffer, count, pos);
209 break;
210 }
211 if ((ssize_t) size > 0)
212 *offset = pos + size;
213 return size;
214}
215
216static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
217 size_t count, loff_t * offset)
218{
219 snd_info_private_data_t *data;
220 struct snd_info_entry *entry;
221 snd_info_buffer_t *buf;
222 size_t size = 0;
223 loff_t pos;
224
225 data = file->private_data;
226 snd_assert(data != NULL, return -ENXIO);
227 entry = data->entry;
228 pos = *offset;
229 if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
230 return -EIO;
231 if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
232 return -EIO;
233 switch (entry->content) {
234 case SNDRV_INFO_CONTENT_TEXT:
235 buf = data->wbuffer;
236 if (buf == NULL)
237 return -EIO;
238 if (pos >= buf->len)
239 return -ENOMEM;
240 size = buf->len - pos;
241 size = min(count, size);
242 if (copy_from_user(buf->buffer + pos, buffer, size))
243 return -EFAULT;
244 if ((long)buf->size < pos + size)
245 buf->size = pos + size;
246 break;
247 case SNDRV_INFO_CONTENT_DATA:
248 if (entry->c.ops->write)
249 size = entry->c.ops->write(entry,
250 data->file_private_data,
251 file, buffer, count, pos);
252 break;
253 }
254 if ((ssize_t) size > 0)
255 *offset = pos + size;
256 return size;
257}
258
259static int snd_info_entry_open(struct inode *inode, struct file *file)
260{
261 snd_info_entry_t *entry;
262 snd_info_private_data_t *data;
263 snd_info_buffer_t *buffer;
264 struct proc_dir_entry *p;
265 int mode, err;
266
267 down(&info_mutex);
268 p = PDE(inode);
269 entry = p == NULL ? NULL : (snd_info_entry_t *)p->data;
270 if (entry == NULL || entry->disconnected) {
271 up(&info_mutex);
272 return -ENODEV;
273 }
274 if (!try_module_get(entry->module)) {
275 err = -EFAULT;
276 goto __error1;
277 }
278 mode = file->f_flags & O_ACCMODE;
279 if (mode == O_RDONLY || mode == O_RDWR) {
280 if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
281 !entry->c.text.read_size) ||
282 (entry->content == SNDRV_INFO_CONTENT_DATA &&
283 entry->c.ops->read == NULL)) {
284 err = -ENODEV;
285 goto __error;
286 }
287 }
288 if (mode == O_WRONLY || mode == O_RDWR) {
289 if ((entry->content == SNDRV_INFO_CONTENT_TEXT &&
290 !entry->c.text.write_size) ||
291 (entry->content == SNDRV_INFO_CONTENT_DATA &&
292 entry->c.ops->write == NULL)) {
293 err = -ENODEV;
294 goto __error;
295 }
296 }
297 data = kcalloc(1, sizeof(*data), GFP_KERNEL);
298 if (data == NULL) {
299 err = -ENOMEM;
300 goto __error;
301 }
302 data->entry = entry;
303 switch (entry->content) {
304 case SNDRV_INFO_CONTENT_TEXT:
305 if (mode == O_RDONLY || mode == O_RDWR) {
306 buffer = kcalloc(1, sizeof(*buffer), GFP_KERNEL);
307 if (buffer == NULL) {
308 kfree(data);
309 err = -ENOMEM;
310 goto __error;
311 }
312 buffer->len = (entry->c.text.read_size +
313 (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
314 buffer->buffer = vmalloc(buffer->len);
315 if (buffer->buffer == NULL) {
316 kfree(buffer);
317 kfree(data);
318 err = -ENOMEM;
319 goto __error;
320 }
321 buffer->curr = buffer->buffer;
322 data->rbuffer = buffer;
323 }
324 if (mode == O_WRONLY || mode == O_RDWR) {
325 buffer = kcalloc(1, sizeof(*buffer), GFP_KERNEL);
326 if (buffer == NULL) {
327 if (mode == O_RDWR) {
328 vfree(data->rbuffer->buffer);
329 kfree(data->rbuffer);
330 }
331 kfree(data);
332 err = -ENOMEM;
333 goto __error;
334 }
335 buffer->len = (entry->c.text.write_size +
336 (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
337 buffer->buffer = vmalloc(buffer->len);
338 if (buffer->buffer == NULL) {
339 if (mode == O_RDWR) {
340 vfree(data->rbuffer->buffer);
341 kfree(data->rbuffer);
342 }
343 kfree(buffer);
344 kfree(data);
345 err = -ENOMEM;
346 goto __error;
347 }
348 buffer->curr = buffer->buffer;
349 data->wbuffer = buffer;
350 }
351 break;
352 case SNDRV_INFO_CONTENT_DATA: /* data */
353 if (entry->c.ops->open) {
354 if ((err = entry->c.ops->open(entry, mode,
355 &data->file_private_data)) < 0) {
356 kfree(data);
357 goto __error;
358 }
359 }
360 break;
361 }
362 file->private_data = data;
363 up(&info_mutex);
364 if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
365 (mode == O_RDONLY || mode == O_RDWR)) {
366 if (entry->c.text.read) {
367 down(&entry->access);
368 entry->c.text.read(entry, data->rbuffer);
369 up(&entry->access);
370 }
371 }
372 return 0;
373
374 __error:
375 module_put(entry->module);
376 __error1:
377 up(&info_mutex);
378 return err;
379}
380
381static int snd_info_entry_release(struct inode *inode, struct file *file)
382{
383 snd_info_entry_t *entry;
384 snd_info_private_data_t *data;
385 int mode;
386
387 mode = file->f_flags & O_ACCMODE;
388 data = file->private_data;
389 entry = data->entry;
390 switch (entry->content) {
391 case SNDRV_INFO_CONTENT_TEXT:
392 if (mode == O_RDONLY || mode == O_RDWR) {
393 vfree(data->rbuffer->buffer);
394 kfree(data->rbuffer);
395 }
396 if (mode == O_WRONLY || mode == O_RDWR) {
397 if (entry->c.text.write) {
398 entry->c.text.write(entry, data->wbuffer);
399 if (data->wbuffer->error) {
400 snd_printk(KERN_WARNING "data write error to %s (%i)\n",
401 entry->name,
402 data->wbuffer->error);
403 }
404 }
405 vfree(data->wbuffer->buffer);
406 kfree(data->wbuffer);
407 }
408 break;
409 case SNDRV_INFO_CONTENT_DATA:
410 if (entry->c.ops->release)
411 entry->c.ops->release(entry, mode,
412 data->file_private_data);
413 break;
414 }
415 module_put(entry->module);
416 kfree(data);
417 return 0;
418}
419
420static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait)
421{
422 snd_info_private_data_t *data;
423 struct snd_info_entry *entry;
424 unsigned int mask;
425
426 data = file->private_data;
427 if (data == NULL)
428 return 0;
429 entry = data->entry;
430 mask = 0;
431 switch (entry->content) {
432 case SNDRV_INFO_CONTENT_DATA:
433 if (entry->c.ops->poll)
434 return entry->c.ops->poll(entry,
435 data->file_private_data,
436 file, wait);
437 if (entry->c.ops->read)
438 mask |= POLLIN | POLLRDNORM;
439 if (entry->c.ops->write)
440 mask |= POLLOUT | POLLWRNORM;
441 break;
442 }
443 return mask;
444}
445
446static inline int _snd_info_entry_ioctl(struct inode *inode, struct file *file,
447 unsigned int cmd, unsigned long arg)
448{
449 snd_info_private_data_t *data;
450 struct snd_info_entry *entry;
451
452 data = file->private_data;
453 if (data == NULL)
454 return 0;
455 entry = data->entry;
456 switch (entry->content) {
457 case SNDRV_INFO_CONTENT_DATA:
458 if (entry->c.ops->ioctl)
459 return entry->c.ops->ioctl(entry,
460 data->file_private_data,
461 file, cmd, arg);
462 break;
463 }
464 return -ENOTTY;
465}
466
467/* FIXME: need to unlock BKL to allow preemption */
468static int snd_info_entry_ioctl(struct inode *inode, struct file *file,
469 unsigned int cmd, unsigned long arg)
470{
471 int err;
472 unlock_kernel();
473 err = _snd_info_entry_ioctl(inode, file, cmd, arg);
474 lock_kernel();
475 return err;
476}
477
478static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
479{
480 struct inode *inode = file->f_dentry->d_inode;
481 snd_info_private_data_t *data;
482 struct snd_info_entry *entry;
483
484 data = file->private_data;
485 if (data == NULL)
486 return 0;
487 entry = data->entry;
488 switch (entry->content) {
489 case SNDRV_INFO_CONTENT_DATA:
490 if (entry->c.ops->mmap)
491 return entry->c.ops->mmap(entry,
492 data->file_private_data,
493 inode, file, vma);
494 break;
495 }
496 return -ENXIO;
497}
498
499static struct file_operations snd_info_entry_operations =
500{
501 .owner = THIS_MODULE,
502 .llseek = snd_info_entry_llseek,
503 .read = snd_info_entry_read,
504 .write = snd_info_entry_write,
505 .poll = snd_info_entry_poll,
506 .ioctl = snd_info_entry_ioctl,
507 .mmap = snd_info_entry_mmap,
508 .open = snd_info_entry_open,
509 .release = snd_info_entry_release,
510};
511
512/**
513 * snd_create_proc_entry - create a procfs entry
514 * @name: the name of the proc file
515 * @mode: the file permission bits, S_Ixxx
516 * @parent: the parent proc-directory entry
517 *
518 * Creates a new proc file entry with the given name and permission
519 * on the given directory.
520 *
521 * Returns the pointer of new instance or NULL on failure.
522 */
523static struct proc_dir_entry *snd_create_proc_entry(const char *name, mode_t mode,
524 struct proc_dir_entry *parent)
525{
526 struct proc_dir_entry *p;
527 p = create_proc_entry(name, mode, parent);
528 if (p)
529 snd_info_entry_prepare(p);
530 return p;
531}
532
533int __init snd_info_init(void)
534{
535 struct proc_dir_entry *p;
536
537 p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, &proc_root);
538 if (p == NULL)
539 return -ENOMEM;
540 snd_proc_root = p;
541#ifdef CONFIG_SND_OSSEMUL
542 {
543 snd_info_entry_t *entry;
544 if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
545 return -ENOMEM;
546 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
547 if (snd_info_register(entry) < 0) {
548 snd_info_free_entry(entry);
549 return -ENOMEM;
550 }
551 snd_oss_root = entry;
552 }
553#endif
554#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
555 {
556 snd_info_entry_t *entry;
557 if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL)
558 return -ENOMEM;
559 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
560 if (snd_info_register(entry) < 0) {
561 snd_info_free_entry(entry);
562 return -ENOMEM;
563 }
564 snd_seq_root = entry;
565 }
566#endif
567 snd_info_version_init();
568 snd_memory_info_init();
569 snd_minor_info_init();
570 snd_minor_info_oss_init();
571 snd_card_info_init();
572 return 0;
573}
574
575int __exit snd_info_done(void)
576{
577 snd_card_info_done();
578 snd_minor_info_oss_done();
579 snd_minor_info_done();
580 snd_memory_info_done();
581 snd_info_version_done();
582 if (snd_proc_root) {
583#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
584 if (snd_seq_root)
585 snd_info_unregister(snd_seq_root);
586#endif
587#ifdef CONFIG_SND_OSSEMUL
588 if (snd_oss_root)
589 snd_info_unregister(snd_oss_root);
590#endif
591 snd_remove_proc_entry(&proc_root, snd_proc_root);
592 }
593 return 0;
594}
595
596/*
597
598 */
599
600
601/*
602 * create a card proc file
603 * called from init.c
604 */
605int snd_info_card_create(snd_card_t * card)
606{
607 char str[8];
608 snd_info_entry_t *entry;
609
610 snd_assert(card != NULL, return -ENXIO);
611
612 sprintf(str, "card%i", card->number);
613 if ((entry = snd_info_create_module_entry(card->module, str, NULL)) == NULL)
614 return -ENOMEM;
615 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
616 if (snd_info_register(entry) < 0) {
617 snd_info_free_entry(entry);
618 return -ENOMEM;
619 }
620 card->proc_root = entry;
621 return 0;
622}
623
624/*
625 * register the card proc file
626 * called from init.c
627 */
628int snd_info_card_register(snd_card_t * card)
629{
630 struct proc_dir_entry *p;
631
632 snd_assert(card != NULL, return -ENXIO);
633
634 if (!strcmp(card->id, card->proc_root->name))
635 return 0;
636
637 p = proc_symlink(card->id, snd_proc_root, card->proc_root->name);
638 if (p == NULL)
639 return -ENOMEM;
640 card->proc_root_link = p;
641 return 0;
642}
643
644/*
645 * de-register the card proc file
646 * called from init.c
647 */
648int snd_info_card_free(snd_card_t * card)
649{
650 snd_assert(card != NULL, return -ENXIO);
651 if (card->proc_root_link) {
652 snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
653 card->proc_root_link = NULL;
654 }
655 if (card->proc_root) {
656 snd_info_unregister(card->proc_root);
657 card->proc_root = NULL;
658 }
659 return 0;
660}
661
662
663/**
664 * snd_info_get_line - read one line from the procfs buffer
665 * @buffer: the procfs buffer
666 * @line: the buffer to store
667 * @len: the max. buffer size - 1
668 *
669 * Reads one line from the buffer and stores the string.
670 *
671 * Returns zero if successful, or 1 if error or EOF.
672 */
673int snd_info_get_line(snd_info_buffer_t * buffer, char *line, int len)
674{
675 int c = -1;
676
677 if (len <= 0 || buffer->stop || buffer->error)
678 return 1;
679 while (--len > 0) {
680 c = *buffer->curr++;
681 if (c == '\n') {
682 if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
683 buffer->stop = 1;
684 }
685 break;
686 }
687 *line++ = c;
688 if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
689 buffer->stop = 1;
690 break;
691 }
692 }
693 while (c != '\n' && !buffer->stop) {
694 c = *buffer->curr++;
695 if ((buffer->curr - buffer->buffer) >= (long)buffer->size) {
696 buffer->stop = 1;
697 }
698 }
699 *line = '\0';
700 return 0;
701}
702
703/**
704 * snd_info_get_line - parse a string token
705 * @dest: the buffer to store the string token
706 * @src: the original string
707 * @len: the max. length of token - 1
708 *
709 * Parses the original string and copy a token to the given
710 * string buffer.
711 *
712 * Returns the updated pointer of the original string so that
713 * it can be used for the next call.
714 */
715char *snd_info_get_str(char *dest, char *src, int len)
716{
717 int c;
718
719 while (*src == ' ' || *src == '\t')
720 src++;
721 if (*src == '"' || *src == '\'') {
722 c = *src++;
723 while (--len > 0 && *src && *src != c) {
724 *dest++ = *src++;
725 }
726 if (*src == c)
727 src++;
728 } else {
729 while (--len > 0 && *src && *src != ' ' && *src != '\t') {
730 *dest++ = *src++;
731 }
732 }
733 *dest = 0;
734 while (*src == ' ' || *src == '\t')
735 src++;
736 return src;
737}
738
739/**
740 * snd_info_create_entry - create an info entry
741 * @name: the proc file name
742 *
743 * Creates an info entry with the given file name and initializes as
744 * the default state.
745 *
746 * Usually called from other functions such as
747 * snd_info_create_card_entry().
748 *
749 * Returns the pointer of the new instance, or NULL on failure.
750 */
751static snd_info_entry_t *snd_info_create_entry(const char *name)
752{
753 snd_info_entry_t *entry;
754 entry = kcalloc(1, sizeof(*entry), GFP_KERNEL);
755 if (entry == NULL)
756 return NULL;
757 entry->name = snd_kmalloc_strdup(name, GFP_KERNEL);
758 if (entry->name == NULL) {
759 kfree(entry);
760 return NULL;
761 }
762 entry->mode = S_IFREG | S_IRUGO;
763 entry->content = SNDRV_INFO_CONTENT_TEXT;
764 init_MUTEX(&entry->access);
765 return entry;
766}
767
768/**
769 * snd_info_create_module_entry - create an info entry for the given module
770 * @module: the module pointer
771 * @name: the file name
772 * @parent: the parent directory
773 *
774 * Creates a new info entry and assigns it to the given module.
775 *
776 * Returns the pointer of the new instance, or NULL on failure.
777 */
778snd_info_entry_t *snd_info_create_module_entry(struct module * module,
779 const char *name,
780 snd_info_entry_t *parent)
781{
782 snd_info_entry_t *entry = snd_info_create_entry(name);
783 if (entry) {
784 entry->module = module;
785 entry->parent = parent;
786 }
787 return entry;
788}
789
790/**
791 * snd_info_create_card_entry - create an info entry for the given card
792 * @card: the card instance
793 * @name: the file name
794 * @parent: the parent directory
795 *
796 * Creates a new info entry and assigns it to the given card.
797 *
798 * Returns the pointer of the new instance, or NULL on failure.
799 */
800snd_info_entry_t *snd_info_create_card_entry(snd_card_t * card,
801 const char *name,
802 snd_info_entry_t * parent)
803{
804 snd_info_entry_t *entry = snd_info_create_entry(name);
805 if (entry) {
806 entry->module = card->module;
807 entry->card = card;
808 entry->parent = parent;
809 }
810 return entry;
811}
812
813static int snd_info_dev_free_entry(snd_device_t *device)
814{
815 snd_info_entry_t *entry = device->device_data;
816 snd_info_free_entry(entry);
817 return 0;
818}
819
820static int snd_info_dev_register_entry(snd_device_t *device)
821{
822 snd_info_entry_t *entry = device->device_data;
823 return snd_info_register(entry);
824}
825
826static int snd_info_dev_disconnect_entry(snd_device_t *device)
827{
828 snd_info_entry_t *entry = device->device_data;
829 entry->disconnected = 1;
830 return 0;
831}
832
833static int snd_info_dev_unregister_entry(snd_device_t *device)
834{
835 snd_info_entry_t *entry = device->device_data;
836 return snd_info_unregister(entry);
837}
838
839/**
840 * snd_card_proc_new - create an info entry for the given card
841 * @card: the card instance
842 * @name: the file name
843 * @entryp: the pointer to store the new info entry
844 *
845 * Creates a new info entry and assigns it to the given card.
846 * Unlike snd_info_create_card_entry(), this function registers the
847 * info entry as an ALSA device component, so that it can be
848 * unregistered/released without explicit call.
849 * Also, you don't have to register this entry via snd_info_register(),
850 * since this will be registered by snd_card_register() automatically.
851 *
852 * The parent is assumed as card->proc_root.
853 *
854 * For releasing this entry, use snd_device_free() instead of
855 * snd_info_free_entry().
856 *
857 * Returns zero if successful, or a negative error code on failure.
858 */
859int snd_card_proc_new(snd_card_t *card, const char *name,
860 snd_info_entry_t **entryp)
861{
862 static snd_device_ops_t ops = {
863 .dev_free = snd_info_dev_free_entry,
864 .dev_register = snd_info_dev_register_entry,
865 .dev_disconnect = snd_info_dev_disconnect_entry,
866 .dev_unregister = snd_info_dev_unregister_entry
867 };
868 snd_info_entry_t *entry;
869 int err;
870
871 entry = snd_info_create_card_entry(card, name, card->proc_root);
872 if (! entry)
873 return -ENOMEM;
874 if ((err = snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)) < 0) {
875 snd_info_free_entry(entry);
876 return err;
877 }
878 if (entryp)
879 *entryp = entry;
880 return 0;
881}
882
883/**
884 * snd_info_free_entry - release the info entry
885 * @entry: the info entry
886 *
887 * Releases the info entry. Don't call this after registered.
888 */
889void snd_info_free_entry(snd_info_entry_t * entry)
890{
891 if (entry == NULL)
892 return;
893 kfree(entry->name);
894 if (entry->private_free)
895 entry->private_free(entry);
896 kfree(entry);
897}
898
899/**
900 * snd_info_register - register the info entry
901 * @entry: the info entry
902 *
903 * Registers the proc info entry.
904 *
905 * Returns zero if successful, or a negative error code on failure.
906 */
907int snd_info_register(snd_info_entry_t * entry)
908{
909 struct proc_dir_entry *root, *p = NULL;
910
911 snd_assert(entry != NULL, return -ENXIO);
912 root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
913 down(&info_mutex);
914 p = snd_create_proc_entry(entry->name, entry->mode, root);
915 if (!p) {
916 up(&info_mutex);
917 return -ENOMEM;
918 }
919 p->owner = entry->module;
920 if (!S_ISDIR(entry->mode))
921 p->proc_fops = &snd_info_entry_operations;
922 p->size = entry->size;
923 p->data = entry;
924 entry->p = p;
925 up(&info_mutex);
926 return 0;
927}
928
929/**
930 * snd_info_unregister - de-register the info entry
931 * @entry: the info entry
932 *
933 * De-registers the info entry and releases the instance.
934 *
935 * Returns zero if successful, or a negative error code on failure.
936 */
937int snd_info_unregister(snd_info_entry_t * entry)
938{
939 struct proc_dir_entry *root;
940
941 snd_assert(entry != NULL && entry->p != NULL, return -ENXIO);
942 root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
943 snd_assert(root, return -ENXIO);
944 down(&info_mutex);
945 snd_remove_proc_entry(root, entry->p);
946 up(&info_mutex);
947 snd_info_free_entry(entry);
948 return 0;
949}
950
951/*
952
953 */
954
955static snd_info_entry_t *snd_info_version_entry = NULL;
956
957static void snd_info_version_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
958{
959 snd_iprintf(buffer,
960 "Advanced Linux Sound Architecture Driver Version "
961 CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
962 );
963}
964
965static int __init snd_info_version_init(void)
966{
967 snd_info_entry_t *entry;
968
969 entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
970 if (entry == NULL)
971 return -ENOMEM;
972 entry->c.text.read_size = 256;
973 entry->c.text.read = snd_info_version_read;
974 if (snd_info_register(entry) < 0) {
975 snd_info_free_entry(entry);
976 return -ENOMEM;
977 }
978 snd_info_version_entry = entry;
979 return 0;
980}
981
982static int __exit snd_info_version_done(void)
983{
984 if (snd_info_version_entry)
985 snd_info_unregister(snd_info_version_entry);
986 return 0;
987}
988
989#endif /* CONFIG_PROC_FS */
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
new file mode 100644
index 000000000000..f9e4ce443454
--- /dev/null
+++ b/sound/core/info_oss.c
@@ -0,0 +1,137 @@
1/*
2 * Information interface for ALSA driver
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/slab.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/minors.h>
27#include <sound/info.h>
28#include <sound/version.h>
29#include <linux/utsname.h>
30
31#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
32
33/*
34 * OSS compatible part
35 */
36
37static DECLARE_MUTEX(strings);
38static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT];
39static snd_info_entry_t *snd_sndstat_proc_entry;
40
41int snd_oss_info_register(int dev, int num, char *string)
42{
43 char *x;
44
45 snd_assert(dev >= 0 && dev < SNDRV_OSS_INFO_DEV_COUNT, return -ENXIO);
46 snd_assert(num >= 0 && num < SNDRV_CARDS, return -ENXIO);
47 down(&strings);
48 if (string == NULL) {
49 if ((x = snd_sndstat_strings[num][dev]) != NULL) {
50 kfree(x);
51 x = NULL;
52 }
53 } else {
54 x = snd_kmalloc_strdup(string, GFP_KERNEL);
55 if (x == NULL) {
56 up(&strings);
57 return -ENOMEM;
58 }
59 }
60 snd_sndstat_strings[num][dev] = x;
61 up(&strings);
62 return 0;
63}
64
65extern void snd_card_info_read_oss(snd_info_buffer_t * buffer);
66
67static int snd_sndstat_show_strings(snd_info_buffer_t * buf, char *id, int dev)
68{
69 int idx, ok = -1;
70 char *str;
71
72 snd_iprintf(buf, "\n%s:", id);
73 down(&strings);
74 for (idx = 0; idx < SNDRV_CARDS; idx++) {
75 str = snd_sndstat_strings[idx][dev];
76 if (str) {
77 if (ok < 0) {
78 snd_iprintf(buf, "\n");
79 ok++;
80 }
81 snd_iprintf(buf, "%i: %s\n", idx, str);
82 }
83 }
84 up(&strings);
85 if (ok < 0)
86 snd_iprintf(buf, " NOT ENABLED IN CONFIG\n");
87 return ok;
88}
89
90static void snd_sndstat_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
91{
92 snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
93 snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
94 system_utsname.sysname,
95 system_utsname.nodename,
96 system_utsname.release,
97 system_utsname.version,
98 system_utsname.machine);
99 snd_iprintf(buffer, "Config options: 0\n");
100 snd_iprintf(buffer, "\nInstalled drivers: \n");
101 snd_iprintf(buffer, "Type 10: ALSA emulation\n");
102 snd_iprintf(buffer, "\nCard config: \n");
103 snd_card_info_read_oss(buffer);
104 snd_sndstat_show_strings(buffer, "Audio devices", SNDRV_OSS_INFO_DEV_AUDIO);
105 snd_sndstat_show_strings(buffer, "Synth devices", SNDRV_OSS_INFO_DEV_SYNTH);
106 snd_sndstat_show_strings(buffer, "Midi devices", SNDRV_OSS_INFO_DEV_MIDI);
107 snd_sndstat_show_strings(buffer, "Timers", SNDRV_OSS_INFO_DEV_TIMERS);
108 snd_sndstat_show_strings(buffer, "Mixers", SNDRV_OSS_INFO_DEV_MIXERS);
109}
110
111int snd_info_minor_register(void)
112{
113 snd_info_entry_t *entry;
114
115 memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
116 if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
117 entry->c.text.read_size = 2048;
118 entry->c.text.read = snd_sndstat_proc_read;
119 if (snd_info_register(entry) < 0) {
120 snd_info_free_entry(entry);
121 entry = NULL;
122 }
123 }
124 snd_sndstat_proc_entry = entry;
125 return 0;
126}
127
128int snd_info_minor_unregister(void)
129{
130 if (snd_sndstat_proc_entry) {
131 snd_info_unregister(snd_sndstat_proc_entry);
132 snd_sndstat_proc_entry = NULL;
133 }
134 return 0;
135}
136
137#endif /* CONFIG_SND_OSSEMUL */
diff --git a/sound/core/init.c b/sound/core/init.c
new file mode 100644
index 000000000000..3f1fa8eabb72
--- /dev/null
+++ b/sound/core/init.c
@@ -0,0 +1,887 @@
1/*
2 * Initialization routines
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/sched.h>
25#include <linux/file.h>
26#include <linux/slab.h>
27#include <linux/time.h>
28#include <linux/ctype.h>
29#include <linux/pci.h>
30#include <linux/pm.h>
31#include <sound/core.h>
32#include <sound/control.h>
33#include <sound/info.h>
34
35struct snd_shutdown_f_ops {
36 struct file_operations f_ops;
37 struct snd_shutdown_f_ops *next;
38};
39
40unsigned int snd_cards_lock = 0; /* locked for registering/using */
41snd_card_t *snd_cards[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = NULL};
42DEFINE_RWLOCK(snd_card_rwlock);
43
44#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
45int (*snd_mixer_oss_notify_callback)(snd_card_t *card, int free_flag);
46#endif
47
48static void snd_card_id_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
49{
50 snd_iprintf(buffer, "%s\n", entry->card->id);
51}
52
53static void snd_card_free_thread(void * __card);
54
55/**
56 * snd_card_new - create and initialize a soundcard structure
57 * @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
58 * @xid: card identification (ASCII string)
59 * @module: top level module for locking
60 * @extra_size: allocate this extra size after the main soundcard structure
61 *
62 * Creates and initializes a soundcard structure.
63 *
64 * Returns kmallocated snd_card_t structure. Creates the ALSA control interface
65 * (which is blocked until snd_card_register function is called).
66 */
67snd_card_t *snd_card_new(int idx, const char *xid,
68 struct module *module, int extra_size)
69{
70 snd_card_t *card;
71 int err;
72
73 if (extra_size < 0)
74 extra_size = 0;
75 card = kcalloc(1, sizeof(*card) + extra_size, GFP_KERNEL);
76 if (card == NULL)
77 return NULL;
78 if (xid) {
79 if (!snd_info_check_reserved_words(xid))
80 goto __error;
81 strlcpy(card->id, xid, sizeof(card->id));
82 }
83 err = 0;
84 write_lock(&snd_card_rwlock);
85 if (idx < 0) {
86 int idx2;
87 for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
88 if (~snd_cards_lock & idx & 1<<idx2) {
89 idx = idx2;
90 if (idx >= snd_ecards_limit)
91 snd_ecards_limit = idx + 1;
92 break;
93 }
94 } else if (idx < snd_ecards_limit) {
95 if (snd_cards_lock & (1 << idx))
96 err = -ENODEV; /* invalid */
97 } else if (idx < SNDRV_CARDS)
98 snd_ecards_limit = idx + 1; /* increase the limit */
99 else
100 err = -ENODEV;
101 if (idx < 0 || err < 0) {
102 write_unlock(&snd_card_rwlock);
103 snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1);
104 goto __error;
105 }
106 snd_cards_lock |= 1 << idx; /* lock it */
107 write_unlock(&snd_card_rwlock);
108 card->number = idx;
109 card->module = module;
110 INIT_LIST_HEAD(&card->devices);
111 init_rwsem(&card->controls_rwsem);
112 rwlock_init(&card->ctl_files_rwlock);
113 INIT_LIST_HEAD(&card->controls);
114 INIT_LIST_HEAD(&card->ctl_files);
115 spin_lock_init(&card->files_lock);
116 init_waitqueue_head(&card->shutdown_sleep);
117 INIT_WORK(&card->free_workq, snd_card_free_thread, card);
118#ifdef CONFIG_PM
119 init_MUTEX(&card->power_lock);
120 init_waitqueue_head(&card->power_sleep);
121#endif
122 /* the control interface cannot be accessed from the user space until */
123 /* snd_cards_bitmask and snd_cards are set with snd_card_register */
124 if ((err = snd_ctl_create(card)) < 0) {
125 snd_printd("unable to register control minors\n");
126 goto __error;
127 }
128 if ((err = snd_info_card_create(card)) < 0) {
129 snd_printd("unable to create card info\n");
130 goto __error_ctl;
131 }
132 if (extra_size > 0)
133 card->private_data = (char *)card + sizeof(snd_card_t);
134 return card;
135
136 __error_ctl:
137 snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
138 __error:
139 kfree(card);
140 return NULL;
141}
142
143static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
144{
145 return POLLERR | POLLNVAL;
146}
147
148/**
149 * snd_card_disconnect - disconnect all APIs from the file-operations (user space)
150 * @card: soundcard structure
151 *
152 * Disconnects all APIs from the file-operations (user space).
153 *
154 * Returns zero, otherwise a negative error code.
155 *
156 * Note: The current implementation replaces all active file->f_op with special
157 * dummy file operations (they do nothing except release).
158 */
159int snd_card_disconnect(snd_card_t * card)
160{
161 struct snd_monitor_file *mfile;
162 struct file *file;
163 struct snd_shutdown_f_ops *s_f_ops;
164 struct file_operations *f_ops, *old_f_ops;
165 int err;
166
167 spin_lock(&card->files_lock);
168 if (card->shutdown) {
169 spin_unlock(&card->files_lock);
170 return 0;
171 }
172 card->shutdown = 1;
173 spin_unlock(&card->files_lock);
174
175 /* phase 1: disable fops (user space) operations for ALSA API */
176 write_lock(&snd_card_rwlock);
177 snd_cards[card->number] = NULL;
178 write_unlock(&snd_card_rwlock);
179
180 /* phase 2: replace file->f_op with special dummy operations */
181
182 spin_lock(&card->files_lock);
183 mfile = card->files;
184 while (mfile) {
185 file = mfile->file;
186
187 /* it's critical part, use endless loop */
188 /* we have no room to fail */
189 s_f_ops = kmalloc(sizeof(struct snd_shutdown_f_ops), GFP_ATOMIC);
190 if (s_f_ops == NULL)
191 panic("Atomic allocation failed for snd_shutdown_f_ops!");
192
193 f_ops = &s_f_ops->f_ops;
194
195 memset(f_ops, 0, sizeof(*f_ops));
196 f_ops->owner = file->f_op->owner;
197 f_ops->release = file->f_op->release;
198 f_ops->poll = snd_disconnect_poll;
199
200 s_f_ops->next = card->s_f_ops;
201 card->s_f_ops = s_f_ops;
202
203 f_ops = fops_get(f_ops);
204
205 old_f_ops = file->f_op;
206 file->f_op = f_ops; /* must be atomic */
207 fops_put(old_f_ops);
208
209 mfile = mfile->next;
210 }
211 spin_unlock(&card->files_lock);
212
213 /* phase 3: notify all connected devices about disconnection */
214 /* at this point, they cannot respond to any calls except release() */
215
216#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
217 if (snd_mixer_oss_notify_callback)
218 snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_DISCONNECT);
219#endif
220
221 /* notify all devices that we are disconnected */
222 err = snd_device_disconnect_all(card);
223 if (err < 0)
224 snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
225
226 return 0;
227}
228
229#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
230static void snd_generic_device_unregister(struct snd_generic_device *dev);
231#endif
232
233/**
234 * snd_card_free - frees given soundcard structure
235 * @card: soundcard structure
236 *
237 * This function releases the soundcard structure and the all assigned
238 * devices automatically. That is, you don't have to release the devices
239 * by yourself.
240 *
241 * Returns zero. Frees all associated devices and frees the control
242 * interface associated to given soundcard.
243 */
244int snd_card_free(snd_card_t * card)
245{
246 struct snd_shutdown_f_ops *s_f_ops;
247
248 if (card == NULL)
249 return -EINVAL;
250 write_lock(&snd_card_rwlock);
251 snd_cards[card->number] = NULL;
252 write_unlock(&snd_card_rwlock);
253
254#ifdef CONFIG_PM
255 wake_up(&card->power_sleep);
256#ifdef CONFIG_SND_GENERIC_PM
257 if (card->pm_dev) {
258 snd_generic_device_unregister(card->pm_dev);
259 card->pm_dev = NULL;
260 }
261#endif
262#endif
263
264 /* wait, until all devices are ready for the free operation */
265 wait_event(card->shutdown_sleep, card->files == NULL);
266
267#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
268 if (snd_mixer_oss_notify_callback)
269 snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
270#endif
271 if (snd_device_free_all(card, SNDRV_DEV_CMD_PRE) < 0) {
272 snd_printk(KERN_ERR "unable to free all devices (pre)\n");
273 /* Fatal, but this situation should never occur */
274 }
275 if (snd_device_free_all(card, SNDRV_DEV_CMD_NORMAL) < 0) {
276 snd_printk(KERN_ERR "unable to free all devices (normal)\n");
277 /* Fatal, but this situation should never occur */
278 }
279 if (snd_device_free_all(card, SNDRV_DEV_CMD_POST) < 0) {
280 snd_printk(KERN_ERR "unable to free all devices (post)\n");
281 /* Fatal, but this situation should never occur */
282 }
283 if (card->private_free)
284 card->private_free(card);
285 if (card->proc_id)
286 snd_info_unregister(card->proc_id);
287 if (snd_info_card_free(card) < 0) {
288 snd_printk(KERN_WARNING "unable to free card info\n");
289 /* Not fatal error */
290 }
291 while (card->s_f_ops) {
292 s_f_ops = card->s_f_ops;
293 card->s_f_ops = s_f_ops->next;
294 kfree(s_f_ops);
295 }
296 write_lock(&snd_card_rwlock);
297 snd_cards_lock &= ~(1 << card->number);
298 write_unlock(&snd_card_rwlock);
299 kfree(card);
300 return 0;
301}
302
303static void snd_card_free_thread(void * __card)
304{
305 snd_card_t *card = __card;
306 struct module * module = card->module;
307
308 if (!try_module_get(module)) {
309 snd_printk(KERN_ERR "unable to lock toplevel module for card %i in free thread\n", card->number);
310 module = NULL;
311 }
312
313 snd_card_free(card);
314
315 module_put(module);
316}
317
318/**
319 * snd_card_free_in_thread - call snd_card_free() in thread
320 * @card: soundcard structure
321 *
322 * This function schedules the call of snd_card_free() function in a
323 * work queue. When all devices are released (non-busy), the work
324 * is woken up and calls snd_card_free().
325 *
326 * When a card can be disconnected at any time by hotplug service,
327 * this function should be used in disconnect (or detach) callback
328 * instead of calling snd_card_free() directly.
329 *
330 * Returns - zero otherwise a negative error code if the start of thread failed.
331 */
332int snd_card_free_in_thread(snd_card_t * card)
333{
334 if (card->files == NULL) {
335 snd_card_free(card);
336 return 0;
337 }
338
339 if (schedule_work(&card->free_workq))
340 return 0;
341
342 snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number);
343 /* try to free the structure immediately */
344 snd_card_free(card);
345 return -EFAULT;
346}
347
348static void choose_default_id(snd_card_t * card)
349{
350 int i, len, idx_flag = 0, loops = 8;
351 char *id, *spos;
352
353 id = spos = card->shortname;
354 while (*id != '\0') {
355 if (*id == ' ')
356 spos = id + 1;
357 id++;
358 }
359 id = card->id;
360 while (*spos != '\0' && !isalnum(*spos))
361 spos++;
362 if (isdigit(*spos))
363 *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D';
364 while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
365 if (isalnum(*spos))
366 *id++ = *spos;
367 spos++;
368 }
369 *id = '\0';
370
371 id = card->id;
372
373 if (*id == '\0')
374 strcpy(id, "default");
375
376 while (1) {
377 if (loops-- == 0) {
378 snd_printk(KERN_ERR "unable to choose default card id (%s)\n", id);
379 strcpy(card->id, card->proc_root->name);
380 return;
381 }
382 if (!snd_info_check_reserved_words(id))
383 goto __change;
384 for (i = 0; i < snd_ecards_limit; i++) {
385 if (snd_cards[i] && !strcmp(snd_cards[i]->id, id))
386 goto __change;
387 }
388 break;
389
390 __change:
391 len = strlen(id);
392 if (idx_flag)
393 id[len-1]++;
394 else if ((size_t)len <= sizeof(card->id) - 3) {
395 strcat(id, "_1");
396 idx_flag++;
397 } else {
398 spos = id + len - 2;
399 if ((size_t)len <= sizeof(card->id) - 2)
400 spos++;
401 *spos++ = '_';
402 *spos++ = '1';
403 *spos++ = '\0';
404 idx_flag++;
405 }
406 }
407}
408
409/**
410 * snd_card_register - register the soundcard
411 * @card: soundcard structure
412 *
413 * This function registers all the devices assigned to the soundcard.
414 * Until calling this, the ALSA control interface is blocked from the
415 * external accesses. Thus, you should call this function at the end
416 * of the initialization of the card.
417 *
418 * Returns zero otherwise a negative error code if the registrain failed.
419 */
420int snd_card_register(snd_card_t * card)
421{
422 int err;
423 snd_info_entry_t *entry;
424
425 snd_runtime_check(card != NULL, return -EINVAL);
426 if ((err = snd_device_register_all(card)) < 0)
427 return err;
428 write_lock(&snd_card_rwlock);
429 if (snd_cards[card->number]) {
430 /* already registered */
431 write_unlock(&snd_card_rwlock);
432 return 0;
433 }
434 if (card->id[0] == '\0')
435 choose_default_id(card);
436 snd_cards[card->number] = card;
437 write_unlock(&snd_card_rwlock);
438 if ((err = snd_info_card_register(card)) < 0) {
439 snd_printd("unable to create card info\n");
440 goto __skip_info;
441 }
442 if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
443 snd_printd("unable to create card entry\n");
444 goto __skip_info;
445 }
446 entry->c.text.read_size = PAGE_SIZE;
447 entry->c.text.read = snd_card_id_read;
448 if (snd_info_register(entry) < 0) {
449 snd_info_free_entry(entry);
450 entry = NULL;
451 }
452 card->proc_id = entry;
453 __skip_info:
454#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
455 if (snd_mixer_oss_notify_callback)
456 snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
457#endif
458 return 0;
459}
460
461static snd_info_entry_t *snd_card_info_entry = NULL;
462
463static void snd_card_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
464{
465 int idx, count;
466 snd_card_t *card;
467
468 for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
469 read_lock(&snd_card_rwlock);
470 if ((card = snd_cards[idx]) != NULL) {
471 count++;
472 snd_iprintf(buffer, "%i [%-15s]: %s - %s\n",
473 idx,
474 card->id,
475 card->driver,
476 card->shortname);
477 snd_iprintf(buffer, " %s\n",
478 card->longname);
479 }
480 read_unlock(&snd_card_rwlock);
481 }
482 if (!count)
483 snd_iprintf(buffer, "--- no soundcards ---\n");
484}
485
486#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
487
488void snd_card_info_read_oss(snd_info_buffer_t * buffer)
489{
490 int idx, count;
491 snd_card_t *card;
492
493 for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
494 read_lock(&snd_card_rwlock);
495 if ((card = snd_cards[idx]) != NULL) {
496 count++;
497 snd_iprintf(buffer, "%s\n", card->longname);
498 }
499 read_unlock(&snd_card_rwlock);
500 }
501 if (!count) {
502 snd_iprintf(buffer, "--- no soundcards ---\n");
503 }
504}
505
506#endif
507
508#ifdef MODULE
509static snd_info_entry_t *snd_card_module_info_entry;
510static void snd_card_module_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
511{
512 int idx;
513 snd_card_t *card;
514
515 for (idx = 0; idx < SNDRV_CARDS; idx++) {
516 read_lock(&snd_card_rwlock);
517 if ((card = snd_cards[idx]) != NULL)
518 snd_iprintf(buffer, "%i %s\n", idx, card->module->name);
519 read_unlock(&snd_card_rwlock);
520 }
521}
522#endif
523
524int __init snd_card_info_init(void)
525{
526 snd_info_entry_t *entry;
527
528 entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL);
529 snd_runtime_check(entry != NULL, return -ENOMEM);
530 entry->c.text.read_size = PAGE_SIZE;
531 entry->c.text.read = snd_card_info_read;
532 if (snd_info_register(entry) < 0) {
533 snd_info_free_entry(entry);
534 return -ENOMEM;
535 }
536 snd_card_info_entry = entry;
537
538#ifdef MODULE
539 entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
540 if (entry) {
541 entry->c.text.read_size = PAGE_SIZE;
542 entry->c.text.read = snd_card_module_info_read;
543 if (snd_info_register(entry) < 0)
544 snd_info_free_entry(entry);
545 else
546 snd_card_module_info_entry = entry;
547 }
548#endif
549
550 return 0;
551}
552
553int __exit snd_card_info_done(void)
554{
555 if (snd_card_info_entry)
556 snd_info_unregister(snd_card_info_entry);
557#ifdef MODULE
558 if (snd_card_module_info_entry)
559 snd_info_unregister(snd_card_module_info_entry);
560#endif
561 return 0;
562}
563
564/**
565 * snd_component_add - add a component string
566 * @card: soundcard structure
567 * @component: the component id string
568 *
569 * This function adds the component id string to the supported list.
570 * The component can be referred from the alsa-lib.
571 *
572 * Returns zero otherwise a negative error code.
573 */
574
575int snd_component_add(snd_card_t *card, const char *component)
576{
577 char *ptr;
578 int len = strlen(component);
579
580 ptr = strstr(card->components, component);
581 if (ptr != NULL) {
582 if (ptr[len] == '\0' || ptr[len] == ' ') /* already there */
583 return 1;
584 }
585 if (strlen(card->components) + 1 + len + 1 > sizeof(card->components)) {
586 snd_BUG();
587 return -ENOMEM;
588 }
589 if (card->components[0] != '\0')
590 strcat(card->components, " ");
591 strcat(card->components, component);
592 return 0;
593}
594
595/**
596 * snd_card_file_add - add the file to the file list of the card
597 * @card: soundcard structure
598 * @file: file pointer
599 *
600 * This function adds the file to the file linked-list of the card.
601 * This linked-list is used to keep tracking the connection state,
602 * and to avoid the release of busy resources by hotplug.
603 *
604 * Returns zero or a negative error code.
605 */
606int snd_card_file_add(snd_card_t *card, struct file *file)
607{
608 struct snd_monitor_file *mfile;
609
610 mfile = kmalloc(sizeof(*mfile), GFP_KERNEL);
611 if (mfile == NULL)
612 return -ENOMEM;
613 mfile->file = file;
614 mfile->next = NULL;
615 spin_lock(&card->files_lock);
616 if (card->shutdown) {
617 spin_unlock(&card->files_lock);
618 kfree(mfile);
619 return -ENODEV;
620 }
621 mfile->next = card->files;
622 card->files = mfile;
623 spin_unlock(&card->files_lock);
624 return 0;
625}
626
627/**
628 * snd_card_file_remove - remove the file from the file list
629 * @card: soundcard structure
630 * @file: file pointer
631 *
632 * This function removes the file formerly added to the card via
633 * snd_card_file_add() function.
634 * If all files are removed and the release of the card is
635 * scheduled, it will wake up the the thread to call snd_card_free()
636 * (see snd_card_free_in_thread() function).
637 *
638 * Returns zero or a negative error code.
639 */
640int snd_card_file_remove(snd_card_t *card, struct file *file)
641{
642 struct snd_monitor_file *mfile, *pfile = NULL;
643
644 spin_lock(&card->files_lock);
645 mfile = card->files;
646 while (mfile) {
647 if (mfile->file == file) {
648 if (pfile)
649 pfile->next = mfile->next;
650 else
651 card->files = mfile->next;
652 break;
653 }
654 pfile = mfile;
655 mfile = mfile->next;
656 }
657 spin_unlock(&card->files_lock);
658 if (card->files == NULL)
659 wake_up(&card->shutdown_sleep);
660 if (!mfile) {
661 snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
662 return -ENOENT;
663 }
664 kfree(mfile);
665 return 0;
666}
667
668#ifdef CONFIG_PM
669/**
670 * snd_power_wait - wait until the power-state is changed.
671 * @card: soundcard structure
672 * @power_state: expected power state
673 * @file: file structure for the O_NONBLOCK check (optional)
674 *
675 * Waits until the power-state is changed.
676 *
677 * Note: the power lock must be active before call.
678 */
679int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file)
680{
681 wait_queue_t wait;
682 int result = 0;
683
684 /* fastpath */
685 if (snd_power_get_state(card) == power_state)
686 return 0;
687 init_waitqueue_entry(&wait, current);
688 add_wait_queue(&card->power_sleep, &wait);
689 while (1) {
690 if (card->shutdown) {
691 result = -ENODEV;
692 break;
693 }
694 if (snd_power_get_state(card) == power_state)
695 break;
696#if 0 /* block all devices */
697 if (file && (file->f_flags & O_NONBLOCK)) {
698 result = -EAGAIN;
699 break;
700 }
701#endif
702 set_current_state(TASK_UNINTERRUPTIBLE);
703 snd_power_unlock(card);
704 schedule_timeout(30 * HZ);
705 snd_power_lock(card);
706 }
707 remove_wait_queue(&card->power_sleep, &wait);
708 return result;
709}
710
711/**
712 * snd_card_set_pm_callback - set the PCI power-management callbacks
713 * @card: soundcard structure
714 * @suspend: suspend callback function
715 * @resume: resume callback function
716 * @private_data: private data to pass to the callback functions
717 *
718 * Sets the power-management callback functions of the card.
719 * These callbacks are called from ALSA's common PCI suspend/resume
720 * handler and from the control API.
721 */
722int snd_card_set_pm_callback(snd_card_t *card,
723 int (*suspend)(snd_card_t *, pm_message_t),
724 int (*resume)(snd_card_t *),
725 void *private_data)
726{
727 card->pm_suspend = suspend;
728 card->pm_resume = resume;
729 card->pm_private_data = private_data;
730 return 0;
731}
732
733#ifdef CONFIG_SND_GENERIC_PM
734/*
735 * use platform_device for generic power-management without a proper bus
736 * (e.g. ISA)
737 */
738struct snd_generic_device {
739 struct platform_device pdev;
740 snd_card_t *card;
741};
742
743#define get_snd_generic_card(dev) container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card
744
745#define SND_GENERIC_NAME "snd_generic_pm"
746
747static int snd_generic_suspend(struct device *dev, u32 state, u32 level);
748static int snd_generic_resume(struct device *dev, u32 level);
749
750static struct device_driver snd_generic_driver = {
751 .name = SND_GENERIC_NAME,
752 .bus = &platform_bus_type,
753 .suspend = snd_generic_suspend,
754 .resume = snd_generic_resume,
755};
756
757static int generic_driver_registered;
758
759static void generic_driver_unregister(void)
760{
761 if (generic_driver_registered) {
762 generic_driver_registered--;
763 if (! generic_driver_registered)
764 driver_unregister(&snd_generic_driver);
765 }
766}
767
768static struct snd_generic_device *snd_generic_device_register(snd_card_t *card)
769{
770 struct snd_generic_device *dev;
771
772 if (! generic_driver_registered) {
773 if (driver_register(&snd_generic_driver) < 0)
774 return NULL;
775 }
776 generic_driver_registered++;
777
778 dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
779 if (! dev) {
780 generic_driver_unregister();
781 return NULL;
782 }
783
784 dev->pdev.name = SND_GENERIC_NAME;
785 dev->pdev.id = card->number;
786 dev->card = card;
787 if (platform_device_register(&dev->pdev) < 0) {
788 kfree(dev);
789 generic_driver_unregister();
790 return NULL;
791 }
792 return dev;
793}
794
795static void snd_generic_device_unregister(struct snd_generic_device *dev)
796{
797 platform_device_unregister(&dev->pdev);
798 kfree(dev);
799 generic_driver_unregister();
800}
801
802/* suspend/resume callbacks for snd_generic platform device */
803static int snd_generic_suspend(struct device *dev, u32 state, u32 level)
804{
805 snd_card_t *card;
806
807 if (level != SUSPEND_DISABLE)
808 return 0;
809
810 card = get_snd_generic_card(dev);
811 if (card->power_state == SNDRV_CTL_POWER_D3hot)
812 return 0;
813 card->pm_suspend(card, PMSG_SUSPEND);
814 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
815 return 0;
816}
817
818static int snd_generic_resume(struct device *dev, u32 level)
819{
820 snd_card_t *card;
821
822 if (level != RESUME_ENABLE)
823 return 0;
824
825 card = get_snd_generic_card(dev);
826 if (card->power_state == SNDRV_CTL_POWER_D0)
827 return 0;
828 card->pm_resume(card);
829 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
830 return 0;
831}
832
833/**
834 * snd_card_set_generic_pm_callback - set the generic power-management callbacks
835 * @card: soundcard structure
836 * @suspend: suspend callback function
837 * @resume: resume callback function
838 * @private_data: private data to pass to the callback functions
839 *
840 * Registers the power-management and sets the lowlevel callbacks for
841 * the given card. These callbacks are called from the ALSA's common
842 * PM handler and from the control API.
843 */
844int snd_card_set_generic_pm_callback(snd_card_t *card,
845 int (*suspend)(snd_card_t *, pm_message_t),
846 int (*resume)(snd_card_t *),
847 void *private_data)
848{
849 card->pm_dev = snd_generic_device_register(card);
850 if (! card->pm_dev)
851 return -ENOMEM;
852 snd_card_set_pm_callback(card, suspend, resume, private_data);
853 return 0;
854}
855#endif /* CONFIG_SND_GENERIC_PM */
856
857#ifdef CONFIG_PCI
858int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state)
859{
860 snd_card_t *card = pci_get_drvdata(dev);
861 int err;
862 if (! card || ! card->pm_suspend)
863 return 0;
864 if (card->power_state == SNDRV_CTL_POWER_D3hot)
865 return 0;
866 err = card->pm_suspend(card, PMSG_SUSPEND);
867 pci_save_state(dev);
868 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
869 return err;
870}
871
872int snd_card_pci_resume(struct pci_dev *dev)
873{
874 snd_card_t *card = pci_get_drvdata(dev);
875 if (! card || ! card->pm_resume)
876 return 0;
877 if (card->power_state == SNDRV_CTL_POWER_D0)
878 return 0;
879 /* restore the PCI config space */
880 pci_restore_state(dev);
881 card->pm_resume(card);
882 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
883 return 0;
884}
885#endif
886
887#endif /* CONFIG_PM */
diff --git a/sound/core/isadma.c b/sound/core/isadma.c
new file mode 100644
index 000000000000..1a378951da5b
--- /dev/null
+++ b/sound/core/isadma.c
@@ -0,0 +1,103 @@
1/*
2 * ISA DMA support functions
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/*
23 * Defining following add some delay. Maybe this helps for some broken
24 * ISA DMA controllers.
25 */
26
27#undef HAVE_REALLY_SLOW_DMA_CONTROLLER
28
29#include <sound/driver.h>
30#include <sound/core.h>
31#include <asm/dma.h>
32
33/**
34 * snd_dma_program - program an ISA DMA transfer
35 * @dma: the dma number
36 * @addr: the physical address of the buffer
37 * @size: the DMA transfer size
38 * @mode: the DMA transfer mode, DMA_MODE_XXX
39 *
40 * Programs an ISA DMA transfer for the given buffer.
41 */
42void snd_dma_program(unsigned long dma,
43 unsigned long addr, unsigned int size,
44 unsigned short mode)
45{
46 unsigned long flags;
47
48 flags = claim_dma_lock();
49 disable_dma(dma);
50 clear_dma_ff(dma);
51 set_dma_mode(dma, mode);
52 set_dma_addr(dma, addr);
53 set_dma_count(dma, size);
54 if (!(mode & DMA_MODE_NO_ENABLE))
55 enable_dma(dma);
56 release_dma_lock(flags);
57}
58
59/**
60 * snd_dma_disable - stop the ISA DMA transfer
61 * @dma: the dma number
62 *
63 * Stops the ISA DMA transfer.
64 */
65void snd_dma_disable(unsigned long dma)
66{
67 unsigned long flags;
68
69 flags = claim_dma_lock();
70 clear_dma_ff(dma);
71 disable_dma(dma);
72 release_dma_lock(flags);
73}
74
75/**
76 * snd_dma_pointer - return the current pointer to DMA transfer buffer in bytes
77 * @dma: the dma number
78 * @size: the dma transfer size
79 *
80 * Returns the current pointer in DMA tranfer buffer in bytes
81 */
82unsigned int snd_dma_pointer(unsigned long dma, unsigned int size)
83{
84 unsigned long flags;
85 unsigned int result;
86
87 flags = claim_dma_lock();
88 clear_dma_ff(dma);
89 if (!isa_dma_bridge_buggy)
90 disable_dma(dma);
91 result = get_dma_residue(dma);
92 if (!isa_dma_bridge_buggy)
93 enable_dma(dma);
94 release_dma_lock(flags);
95#ifdef CONFIG_SND_DEBUG
96 if (result > size)
97 snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size);
98#endif
99 if (result >= size || result == 0)
100 return 0;
101 else
102 return size - result;
103}
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
new file mode 100644
index 000000000000..344a83fd7c2e
--- /dev/null
+++ b/sound/core/memalloc.c
@@ -0,0 +1,663 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 * Takashi Iwai <tiwai@suse.de>
4 *
5 * Generic memory allocators
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <linux/config.h>
25#include <linux/module.h>
26#include <linux/proc_fs.h>
27#include <linux/init.h>
28#include <linux/pci.h>
29#include <linux/slab.h>
30#include <linux/mm.h>
31#include <linux/dma-mapping.h>
32#include <linux/moduleparam.h>
33#include <asm/semaphore.h>
34#include <sound/memalloc.h>
35#ifdef CONFIG_SBUS
36#include <asm/sbus.h>
37#endif
38
39
40MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
41MODULE_DESCRIPTION("Memory allocator for ALSA system.");
42MODULE_LICENSE("GPL");
43
44
45#ifndef SNDRV_CARDS
46#define SNDRV_CARDS 8
47#endif
48
49/* FIXME: so far only some PCI devices have the preallocation table */
50#ifdef CONFIG_PCI
51static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
52module_param_array(enable, bool, NULL, 0444);
53MODULE_PARM_DESC(enable, "Enable cards to allocate buffers.");
54#endif
55
56/*
57 */
58
59void *snd_malloc_sgbuf_pages(struct device *device,
60 size_t size, struct snd_dma_buffer *dmab,
61 size_t *res_size);
62int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
63
64/*
65 */
66
67static DECLARE_MUTEX(list_mutex);
68static LIST_HEAD(mem_list_head);
69
70/* buffer preservation list */
71struct snd_mem_list {
72 struct snd_dma_buffer buffer;
73 unsigned int id;
74 struct list_head list;
75};
76
77/* id for pre-allocated buffers */
78#define SNDRV_DMA_DEVICE_UNUSED (unsigned int)-1
79
80#ifdef CONFIG_SND_DEBUG
81#define __ASTRING__(x) #x
82#define snd_assert(expr, args...) do {\
83 if (!(expr)) {\
84 printk(KERN_ERR "snd-malloc: BUG? (%s) (called from %p)\n", __ASTRING__(expr), __builtin_return_address(0));\
85 args;\
86 }\
87} while (0)
88#else
89#define snd_assert(expr, args...) /**/
90#endif
91
92/*
93 * Hacks
94 */
95
96#if defined(__i386__) || defined(__ppc__) || defined(__x86_64__)
97/*
98 * A hack to allocate large buffers via dma_alloc_coherent()
99 *
100 * since dma_alloc_coherent always tries GFP_DMA when the requested
101 * pci memory region is below 32bit, it happens quite often that even
102 * 2 order of pages cannot be allocated.
103 *
104 * so in the following, we allocate at first without dma_mask, so that
105 * allocation will be done without GFP_DMA. if the area doesn't match
106 * with the requested region, then realloate with the original dma_mask
107 * again.
108 *
109 * Really, we want to move this type of thing into dma_alloc_coherent()
110 * so dma_mask doesn't have to be messed with.
111 */
112
113static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size,
114 dma_addr_t *dma_handle, int flags)
115{
116 void *ret;
117 u64 dma_mask, coherent_dma_mask;
118
119 if (dev == NULL || !dev->dma_mask)
120 return dma_alloc_coherent(dev, size, dma_handle, flags);
121 dma_mask = *dev->dma_mask;
122 coherent_dma_mask = dev->coherent_dma_mask;
123 *dev->dma_mask = 0xffffffff; /* do without masking */
124 dev->coherent_dma_mask = 0xffffffff; /* do without masking */
125 ret = dma_alloc_coherent(dev, size, dma_handle, flags);
126 *dev->dma_mask = dma_mask; /* restore */
127 dev->coherent_dma_mask = coherent_dma_mask; /* restore */
128 if (ret) {
129 /* obtained address is out of range? */
130 if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) {
131 /* reallocate with the proper mask */
132 dma_free_coherent(dev, size, ret, *dma_handle);
133 ret = dma_alloc_coherent(dev, size, dma_handle, flags);
134 }
135 } else {
136 /* wish to success now with the proper mask... */
137 if (dma_mask != 0xffffffffUL) {
138 /* allocation with GFP_ATOMIC to avoid the long stall */
139 flags &= ~GFP_KERNEL;
140 flags |= GFP_ATOMIC;
141 ret = dma_alloc_coherent(dev, size, dma_handle, flags);
142 }
143 }
144 return ret;
145}
146
147/* redefine dma_alloc_coherent for some architectures */
148#undef dma_alloc_coherent
149#define dma_alloc_coherent snd_dma_hack_alloc_coherent
150
151#endif /* arch */
152
153#if ! defined(__arm__)
154#define NEED_RESERVE_PAGES
155#endif
156
157/*
158 *
159 * Generic memory allocators
160 *
161 */
162
163static long snd_allocated_pages; /* holding the number of allocated pages */
164
165static inline void inc_snd_pages(int order)
166{
167 snd_allocated_pages += 1 << order;
168}
169
170static inline void dec_snd_pages(int order)
171{
172 snd_allocated_pages -= 1 << order;
173}
174
175static void mark_pages(struct page *page, int order)
176{
177 struct page *last_page = page + (1 << order);
178 while (page < last_page)
179 SetPageReserved(page++);
180}
181
182static void unmark_pages(struct page *page, int order)
183{
184 struct page *last_page = page + (1 << order);
185 while (page < last_page)
186 ClearPageReserved(page++);
187}
188
189/**
190 * snd_malloc_pages - allocate pages with the given size
191 * @size: the size to allocate in bytes
192 * @gfp_flags: the allocation conditions, GFP_XXX
193 *
194 * Allocates the physically contiguous pages with the given size.
195 *
196 * Returns the pointer of the buffer, or NULL if no enoguh memory.
197 */
198void *snd_malloc_pages(size_t size, unsigned int gfp_flags)
199{
200 int pg;
201 void *res;
202
203 snd_assert(size > 0, return NULL);
204 snd_assert(gfp_flags != 0, return NULL);
205 pg = get_order(size);
206 if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) {
207 mark_pages(virt_to_page(res), pg);
208 inc_snd_pages(pg);
209 }
210 return res;
211}
212
213/**
214 * snd_free_pages - release the pages
215 * @ptr: the buffer pointer to release
216 * @size: the allocated buffer size
217 *
218 * Releases the buffer allocated via snd_malloc_pages().
219 */
220void snd_free_pages(void *ptr, size_t size)
221{
222 int pg;
223
224 if (ptr == NULL)
225 return;
226 pg = get_order(size);
227 dec_snd_pages(pg);
228 unmark_pages(virt_to_page(ptr), pg);
229 free_pages((unsigned long) ptr, pg);
230}
231
232/*
233 *
234 * Bus-specific memory allocators
235 *
236 */
237
238/* allocate the coherent DMA pages */
239static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma)
240{
241 int pg;
242 void *res;
243 unsigned int gfp_flags;
244
245 snd_assert(size > 0, return NULL);
246 snd_assert(dma != NULL, return NULL);
247 pg = get_order(size);
248 gfp_flags = GFP_KERNEL
249 | __GFP_NORETRY /* don't trigger OOM-killer */
250 | __GFP_NOWARN; /* no stack trace print - this call is non-critical */
251 res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags);
252 if (res != NULL) {
253#ifdef NEED_RESERVE_PAGES
254 mark_pages(virt_to_page(res), pg); /* should be dma_to_page() */
255#endif
256 inc_snd_pages(pg);
257 }
258
259 return res;
260}
261
262/* free the coherent DMA pages */
263static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
264 dma_addr_t dma)
265{
266 int pg;
267
268 if (ptr == NULL)
269 return;
270 pg = get_order(size);
271 dec_snd_pages(pg);
272#ifdef NEED_RESERVE_PAGES
273 unmark_pages(virt_to_page(ptr), pg); /* should be dma_to_page() */
274#endif
275 dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma);
276}
277
278#ifdef CONFIG_SBUS
279
280static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
281 dma_addr_t *dma_addr)
282{
283 struct sbus_dev *sdev = (struct sbus_dev *)dev;
284 int pg;
285 void *res;
286
287 snd_assert(size > 0, return NULL);
288 snd_assert(dma_addr != NULL, return NULL);
289 pg = get_order(size);
290 res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
291 if (res != NULL)
292 inc_snd_pages(pg);
293 return res;
294}
295
296static void snd_free_sbus_pages(struct device *dev, size_t size,
297 void *ptr, dma_addr_t dma_addr)
298{
299 struct sbus_dev *sdev = (struct sbus_dev *)dev;
300 int pg;
301
302 if (ptr == NULL)
303 return;
304 pg = get_order(size);
305 dec_snd_pages(pg);
306 sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
307}
308
309#endif /* CONFIG_SBUS */
310
311/*
312 *
313 * ALSA generic memory management
314 *
315 */
316
317
318/**
319 * snd_dma_alloc_pages - allocate the buffer area according to the given type
320 * @type: the DMA buffer type
321 * @device: the device pointer
322 * @size: the buffer size to allocate
323 * @dmab: buffer allocation record to store the allocated data
324 *
325 * Calls the memory-allocator function for the corresponding
326 * buffer type.
327 *
328 * Returns zero if the buffer with the given size is allocated successfuly,
329 * other a negative value at error.
330 */
331int snd_dma_alloc_pages(int type, struct device *device, size_t size,
332 struct snd_dma_buffer *dmab)
333{
334 snd_assert(size > 0, return -ENXIO);
335 snd_assert(dmab != NULL, return -ENXIO);
336
337 dmab->dev.type = type;
338 dmab->dev.dev = device;
339 dmab->bytes = 0;
340 switch (type) {
341 case SNDRV_DMA_TYPE_CONTINUOUS:
342 dmab->area = snd_malloc_pages(size, (unsigned long)device);
343 dmab->addr = 0;
344 break;
345#ifdef CONFIG_SBUS
346 case SNDRV_DMA_TYPE_SBUS:
347 dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
348 break;
349#endif
350 case SNDRV_DMA_TYPE_DEV:
351 dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
352 break;
353 case SNDRV_DMA_TYPE_DEV_SG:
354 snd_malloc_sgbuf_pages(device, size, dmab, NULL);
355 break;
356 default:
357 printk(KERN_ERR "snd-malloc: invalid device type %d\n", type);
358 dmab->area = NULL;
359 dmab->addr = 0;
360 return -ENXIO;
361 }
362 if (! dmab->area)
363 return -ENOMEM;
364 dmab->bytes = size;
365 return 0;
366}
367
368/**
369 * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback
370 * @type: the DMA buffer type
371 * @device: the device pointer
372 * @size: the buffer size to allocate
373 * @dmab: buffer allocation record to store the allocated data
374 *
375 * Calls the memory-allocator function for the corresponding
376 * buffer type. When no space is left, this function reduces the size and
377 * tries to allocate again. The size actually allocated is stored in
378 * res_size argument.
379 *
380 * Returns zero if the buffer with the given size is allocated successfuly,
381 * other a negative value at error.
382 */
383int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
384 struct snd_dma_buffer *dmab)
385{
386 int err;
387
388 snd_assert(size > 0, return -ENXIO);
389 snd_assert(dmab != NULL, return -ENXIO);
390
391 while ((err = snd_dma_alloc_pages(type, device, size, dmab)) < 0) {
392 if (err != -ENOMEM)
393 return err;
394 size >>= 1;
395 if (size <= PAGE_SIZE)
396 return -ENOMEM;
397 }
398 if (! dmab->area)
399 return -ENOMEM;
400 return 0;
401}
402
403
404/**
405 * snd_dma_free_pages - release the allocated buffer
406 * @dmab: the buffer allocation record to release
407 *
408 * Releases the allocated buffer via snd_dma_alloc_pages().
409 */
410void snd_dma_free_pages(struct snd_dma_buffer *dmab)
411{
412 switch (dmab->dev.type) {
413 case SNDRV_DMA_TYPE_CONTINUOUS:
414 snd_free_pages(dmab->area, dmab->bytes);
415 break;
416#ifdef CONFIG_SBUS
417 case SNDRV_DMA_TYPE_SBUS:
418 snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
419 break;
420#endif
421 case SNDRV_DMA_TYPE_DEV:
422 snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
423 break;
424 case SNDRV_DMA_TYPE_DEV_SG:
425 snd_free_sgbuf_pages(dmab);
426 break;
427 default:
428 printk(KERN_ERR "snd-malloc: invalid device type %d\n", dmab->dev.type);
429 }
430}
431
432
433/**
434 * snd_dma_get_reserved - get the reserved buffer for the given device
435 * @dmab: the buffer allocation record to store
436 * @id: the buffer id
437 *
438 * Looks for the reserved-buffer list and re-uses if the same buffer
439 * is found in the list. When the buffer is found, it's removed from the free list.
440 *
441 * Returns the size of buffer if the buffer is found, or zero if not found.
442 */
443size_t snd_dma_get_reserved_buf(struct snd_dma_buffer *dmab, unsigned int id)
444{
445 struct list_head *p;
446 struct snd_mem_list *mem;
447
448 snd_assert(dmab, return 0);
449
450 down(&list_mutex);
451 list_for_each(p, &mem_list_head) {
452 mem = list_entry(p, struct snd_mem_list, list);
453 if (mem->id == id &&
454 ! memcmp(&mem->buffer.dev, &dmab->dev, sizeof(dmab->dev))) {
455 list_del(p);
456 *dmab = mem->buffer;
457 kfree(mem);
458 up(&list_mutex);
459 return dmab->bytes;
460 }
461 }
462 up(&list_mutex);
463 return 0;
464}
465
466/**
467 * snd_dma_reserve_buf - reserve the buffer
468 * @dmab: the buffer to reserve
469 * @id: the buffer id
470 *
471 * Reserves the given buffer as a reserved buffer.
472 *
473 * Returns zero if successful, or a negative code at error.
474 */
475int snd_dma_reserve_buf(struct snd_dma_buffer *dmab, unsigned int id)
476{
477 struct snd_mem_list *mem;
478
479 snd_assert(dmab, return -EINVAL);
480 mem = kmalloc(sizeof(*mem), GFP_KERNEL);
481 if (! mem)
482 return -ENOMEM;
483 down(&list_mutex);
484 mem->buffer = *dmab;
485 mem->id = id;
486 list_add_tail(&mem->list, &mem_list_head);
487 up(&list_mutex);
488 return 0;
489}
490
491/*
492 * purge all reserved buffers
493 */
494static void free_all_reserved_pages(void)
495{
496 struct list_head *p;
497 struct snd_mem_list *mem;
498
499 down(&list_mutex);
500 while (! list_empty(&mem_list_head)) {
501 p = mem_list_head.next;
502 mem = list_entry(p, struct snd_mem_list, list);
503 list_del(p);
504 snd_dma_free_pages(&mem->buffer);
505 kfree(mem);
506 }
507 up(&list_mutex);
508}
509
510
511
512/*
513 * allocation of buffers for pre-defined devices
514 */
515
516#ifdef CONFIG_PCI
517/* FIXME: for pci only - other bus? */
518struct prealloc_dev {
519 unsigned short vendor;
520 unsigned short device;
521 unsigned long dma_mask;
522 unsigned int size;
523 unsigned int buffers;
524};
525
526#define HAMMERFALL_BUFFER_SIZE (16*1024*4*(26+1)+0x10000)
527
528static struct prealloc_dev prealloc_devices[] __initdata = {
529 {
530 /* hammerfall */
531 .vendor = 0x10ee,
532 .device = 0x3fc4,
533 .dma_mask = 0xffffffff,
534 .size = HAMMERFALL_BUFFER_SIZE,
535 .buffers = 2
536 },
537 {
538 /* HDSP */
539 .vendor = 0x10ee,
540 .device = 0x3fc5,
541 .dma_mask = 0xffffffff,
542 .size = HAMMERFALL_BUFFER_SIZE,
543 .buffers = 2
544 },
545 { }, /* terminator */
546};
547
548static void __init preallocate_cards(void)
549{
550 struct pci_dev *pci = NULL;
551 int card;
552
553 card = 0;
554
555 while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
556 struct prealloc_dev *dev;
557 unsigned int i;
558 if (card >= SNDRV_CARDS)
559 break;
560 for (dev = prealloc_devices; dev->vendor; dev++) {
561 if (dev->vendor == pci->vendor && dev->device == pci->device)
562 break;
563 }
564 if (! dev->vendor)
565 continue;
566 if (! enable[card++]) {
567 printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device);
568 continue;
569 }
570
571 if (pci_set_dma_mask(pci, dev->dma_mask) < 0 ||
572 pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) {
573 printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device);
574 continue;
575 }
576 for (i = 0; i < dev->buffers; i++) {
577 struct snd_dma_buffer dmab;
578 memset(&dmab, 0, sizeof(dmab));
579 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci),
580 dev->size, &dmab) < 0)
581 printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size);
582 else
583 snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci));
584 }
585 }
586}
587#else
588#define preallocate_cards() /* NOP */
589#endif
590
591
592#ifdef CONFIG_PROC_FS
593/*
594 * proc file interface
595 */
596static int snd_mem_proc_read(char *page, char **start, off_t off,
597 int count, int *eof, void *data)
598{
599 int len = 0;
600 long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
601 struct list_head *p;
602 struct snd_mem_list *mem;
603 int devno;
604 static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
605
606 down(&list_mutex);
607 len += snprintf(page + len, count - len,
608 "pages : %li bytes (%li pages per %likB)\n",
609 pages * PAGE_SIZE, pages, PAGE_SIZE / 1024);
610 devno = 0;
611 list_for_each(p, &mem_list_head) {
612 mem = list_entry(p, struct snd_mem_list, list);
613 devno++;
614 len += snprintf(page + len, count - len,
615 "buffer %d : ID %08x : type %s\n",
616 devno, mem->id, types[mem->buffer.dev.type]);
617 len += snprintf(page + len, count - len,
618 " addr = 0x%lx, size = %d bytes\n",
619 (unsigned long)mem->buffer.addr, (int)mem->buffer.bytes);
620 }
621 up(&list_mutex);
622 return len;
623}
624#endif /* CONFIG_PROC_FS */
625
626/*
627 * module entry
628 */
629
630static int __init snd_mem_init(void)
631{
632#ifdef CONFIG_PROC_FS
633 create_proc_read_entry("driver/snd-page-alloc", 0, NULL, snd_mem_proc_read, NULL);
634#endif
635 preallocate_cards();
636 return 0;
637}
638
639static void __exit snd_mem_exit(void)
640{
641 remove_proc_entry("driver/snd-page-alloc", NULL);
642 free_all_reserved_pages();
643 if (snd_allocated_pages > 0)
644 printk(KERN_ERR "snd-malloc: Memory leak? pages not freed = %li\n", snd_allocated_pages);
645}
646
647
648module_init(snd_mem_init)
649module_exit(snd_mem_exit)
650
651
652/*
653 * exports
654 */
655EXPORT_SYMBOL(snd_dma_alloc_pages);
656EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
657EXPORT_SYMBOL(snd_dma_free_pages);
658
659EXPORT_SYMBOL(snd_dma_get_reserved_buf);
660EXPORT_SYMBOL(snd_dma_reserve_buf);
661
662EXPORT_SYMBOL(snd_malloc_pages);
663EXPORT_SYMBOL(snd_free_pages);
diff --git a/sound/core/memory.c b/sound/core/memory.c
new file mode 100644
index 000000000000..20860fec9364
--- /dev/null
+++ b/sound/core/memory.c
@@ -0,0 +1,306 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
3 *
4 * Memory allocation helpers.
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <asm/io.h>
25#include <asm/uaccess.h>
26#include <linux/init.h>
27#include <linux/slab.h>
28#include <linux/time.h>
29#include <linux/pci.h>
30#include <sound/core.h>
31#include <sound/info.h>
32
33/*
34 * memory allocation helpers and debug routines
35 */
36
37#ifdef CONFIG_SND_DEBUG_MEMORY
38
39struct snd_alloc_track {
40 unsigned long magic;
41 void *caller;
42 size_t size;
43 struct list_head list;
44 long data[0];
45};
46
47#define snd_alloc_track_entry(obj) (struct snd_alloc_track *)((char*)obj - (unsigned long)((struct snd_alloc_track *)0)->data)
48
49static long snd_alloc_kmalloc;
50static long snd_alloc_vmalloc;
51static LIST_HEAD(snd_alloc_kmalloc_list);
52static LIST_HEAD(snd_alloc_vmalloc_list);
53static DEFINE_SPINLOCK(snd_alloc_kmalloc_lock);
54static DEFINE_SPINLOCK(snd_alloc_vmalloc_lock);
55#define KMALLOC_MAGIC 0x87654321
56#define VMALLOC_MAGIC 0x87654320
57static snd_info_entry_t *snd_memory_info_entry;
58
59void snd_memory_init(void)
60{
61 snd_alloc_kmalloc = 0;
62 snd_alloc_vmalloc = 0;
63}
64
65void snd_memory_done(void)
66{
67 struct list_head *head;
68 struct snd_alloc_track *t;
69
70 if (snd_alloc_kmalloc > 0)
71 snd_printk(KERN_ERR "Not freed snd_alloc_kmalloc = %li\n", snd_alloc_kmalloc);
72 if (snd_alloc_vmalloc > 0)
73 snd_printk(KERN_ERR "Not freed snd_alloc_vmalloc = %li\n", snd_alloc_vmalloc);
74 list_for_each_prev(head, &snd_alloc_kmalloc_list) {
75 t = list_entry(head, struct snd_alloc_track, list);
76 if (t->magic != KMALLOC_MAGIC) {
77 snd_printk(KERN_ERR "Corrupted kmalloc\n");
78 break;
79 }
80 snd_printk(KERN_ERR "kmalloc(%ld) from %p not freed\n", (long) t->size, t->caller);
81 }
82 list_for_each_prev(head, &snd_alloc_vmalloc_list) {
83 t = list_entry(head, struct snd_alloc_track, list);
84 if (t->magic != VMALLOC_MAGIC) {
85 snd_printk(KERN_ERR "Corrupted vmalloc\n");
86 break;
87 }
88 snd_printk(KERN_ERR "vmalloc(%ld) from %p not freed\n", (long) t->size, t->caller);
89 }
90}
91
92static void *__snd_kmalloc(size_t size, int flags, void *caller)
93{
94 unsigned long cpu_flags;
95 struct snd_alloc_track *t;
96 void *ptr;
97
98 ptr = snd_wrapper_kmalloc(size + sizeof(struct snd_alloc_track), flags);
99 if (ptr != NULL) {
100 t = (struct snd_alloc_track *)ptr;
101 t->magic = KMALLOC_MAGIC;
102 t->caller = caller;
103 spin_lock_irqsave(&snd_alloc_kmalloc_lock, cpu_flags);
104 list_add_tail(&t->list, &snd_alloc_kmalloc_list);
105 spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, cpu_flags);
106 t->size = size;
107 snd_alloc_kmalloc += size;
108 ptr = t->data;
109 }
110 return ptr;
111}
112
113#define _snd_kmalloc(size, flags) __snd_kmalloc((size), (flags), __builtin_return_address(0));
114void *snd_hidden_kmalloc(size_t size, int flags)
115{
116 return _snd_kmalloc(size, flags);
117}
118
119void *snd_hidden_kcalloc(size_t n, size_t size, int flags)
120{
121 void *ret = NULL;
122 if (n != 0 && size > INT_MAX / n)
123 return ret;
124 ret = _snd_kmalloc(n * size, flags);
125 if (ret)
126 memset(ret, 0, n * size);
127 return ret;
128}
129
130void snd_hidden_kfree(const void *obj)
131{
132 unsigned long flags;
133 struct snd_alloc_track *t;
134 if (obj == NULL)
135 return;
136 t = snd_alloc_track_entry(obj);
137 if (t->magic != KMALLOC_MAGIC) {
138 snd_printk(KERN_WARNING "bad kfree (called from %p)\n", __builtin_return_address(0));
139 return;
140 }
141 spin_lock_irqsave(&snd_alloc_kmalloc_lock, flags);
142 list_del(&t->list);
143 spin_unlock_irqrestore(&snd_alloc_kmalloc_lock, flags);
144 t->magic = 0;
145 snd_alloc_kmalloc -= t->size;
146 obj = t;
147 snd_wrapper_kfree(obj);
148}
149
150void *snd_hidden_vmalloc(unsigned long size)
151{
152 void *ptr;
153 ptr = snd_wrapper_vmalloc(size + sizeof(struct snd_alloc_track));
154 if (ptr) {
155 struct snd_alloc_track *t = (struct snd_alloc_track *)ptr;
156 t->magic = VMALLOC_MAGIC;
157 t->caller = __builtin_return_address(0);
158 spin_lock(&snd_alloc_vmalloc_lock);
159 list_add_tail(&t->list, &snd_alloc_vmalloc_list);
160 spin_unlock(&snd_alloc_vmalloc_lock);
161 t->size = size;
162 snd_alloc_vmalloc += size;
163 ptr = t->data;
164 }
165 return ptr;
166}
167
168void snd_hidden_vfree(void *obj)
169{
170 struct snd_alloc_track *t;
171 if (obj == NULL)
172 return;
173 t = snd_alloc_track_entry(obj);
174 if (t->magic != VMALLOC_MAGIC) {
175 snd_printk(KERN_ERR "bad vfree (called from %p)\n", __builtin_return_address(0));
176 return;
177 }
178 spin_lock(&snd_alloc_vmalloc_lock);
179 list_del(&t->list);
180 spin_unlock(&snd_alloc_vmalloc_lock);
181 t->magic = 0;
182 snd_alloc_vmalloc -= t->size;
183 obj = t;
184 snd_wrapper_vfree(obj);
185}
186
187static void snd_memory_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
188{
189 snd_iprintf(buffer, "kmalloc: %li bytes\n", snd_alloc_kmalloc);
190 snd_iprintf(buffer, "vmalloc: %li bytes\n", snd_alloc_vmalloc);
191}
192
193int __init snd_memory_info_init(void)
194{
195 snd_info_entry_t *entry;
196
197 entry = snd_info_create_module_entry(THIS_MODULE, "meminfo", NULL);
198 if (entry) {
199 entry->c.text.read_size = 256;
200 entry->c.text.read = snd_memory_info_read;
201 if (snd_info_register(entry) < 0) {
202 snd_info_free_entry(entry);
203 entry = NULL;
204 }
205 }
206 snd_memory_info_entry = entry;
207 return 0;
208}
209
210int __exit snd_memory_info_done(void)
211{
212 if (snd_memory_info_entry)
213 snd_info_unregister(snd_memory_info_entry);
214 return 0;
215}
216
217#else
218
219#define _snd_kmalloc kmalloc
220
221#endif /* CONFIG_SND_DEBUG_MEMORY */
222
223/**
224 * snd_kmalloc_strdup - copy the string
225 * @string: the original string
226 * @flags: allocation conditions, GFP_XXX
227 *
228 * Allocates a memory chunk via kmalloc() and copies the string to it.
229 *
230 * Returns the pointer, or NULL if no enoguh memory.
231 */
232char *snd_kmalloc_strdup(const char *string, int flags)
233{
234 size_t len;
235 char *ptr;
236
237 if (!string)
238 return NULL;
239 len = strlen(string) + 1;
240 ptr = _snd_kmalloc(len, flags);
241 if (ptr)
242 memcpy(ptr, string, len);
243 return ptr;
244}
245
246/**
247 * copy_to_user_fromio - copy data from mmio-space to user-space
248 * @dst: the destination pointer on user-space
249 * @src: the source pointer on mmio
250 * @count: the data size to copy in bytes
251 *
252 * Copies the data from mmio-space to user-space.
253 *
254 * Returns zero if successful, or non-zero on failure.
255 */
256int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count)
257{
258#if defined(__i386__) || defined(CONFIG_SPARC32)
259 return copy_to_user(dst, (const void*)src, count) ? -EFAULT : 0;
260#else
261 char buf[256];
262 while (count) {
263 size_t c = count;
264 if (c > sizeof(buf))
265 c = sizeof(buf);
266 memcpy_fromio(buf, (void __iomem *)src, c);
267 if (copy_to_user(dst, buf, c))
268 return -EFAULT;
269 count -= c;
270 dst += c;
271 src += c;
272 }
273 return 0;
274#endif
275}
276
277/**
278 * copy_from_user_toio - copy data from user-space to mmio-space
279 * @dst: the destination pointer on mmio-space
280 * @src: the source pointer on user-space
281 * @count: the data size to copy in bytes
282 *
283 * Copies the data from user-space to mmio-space.
284 *
285 * Returns zero if successful, or non-zero on failure.
286 */
287int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count)
288{
289#if defined(__i386__) || defined(CONFIG_SPARC32)
290 return copy_from_user((void*)dst, src, count) ? -EFAULT : 0;
291#else
292 char buf[256];
293 while (count) {
294 size_t c = count;
295 if (c > sizeof(buf))
296 c = sizeof(buf);
297 if (copy_from_user(buf, src, c))
298 return -EFAULT;
299 memcpy_toio(dst, buf, c);
300 count -= c;
301 dst += c;
302 src += c;
303 }
304 return 0;
305#endif
306}
diff --git a/sound/core/misc.c b/sound/core/misc.c
new file mode 100644
index 000000000000..1a81fe4df218
--- /dev/null
+++ b/sound/core/misc.c
@@ -0,0 +1,76 @@
1/*
2 * Misc and compatibility things
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/sched.h>
25#include <linux/time.h>
26#include <sound/core.h>
27
28int snd_task_name(struct task_struct *task, char *name, size_t size)
29{
30 unsigned int idx;
31
32 snd_assert(task != NULL && name != NULL && size >= 2, return -EINVAL);
33 for (idx = 0; idx < sizeof(task->comm) && idx + 1 < size; idx++)
34 name[idx] = task->comm[idx];
35 name[idx] = '\0';
36 return 0;
37}
38
39#ifdef CONFIG_SND_VERBOSE_PRINTK
40void snd_verbose_printk(const char *file, int line, const char *format, ...)
41{
42 va_list args;
43
44 if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
45 char tmp[] = "<0>";
46 tmp[1] = format[1];
47 printk("%sALSA %s:%d: ", tmp, file, line);
48 format += 3;
49 } else {
50 printk("ALSA %s:%d: ", file, line);
51 }
52 va_start(args, format);
53 vprintk(format, args);
54 va_end(args);
55}
56#endif
57
58#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
59void snd_verbose_printd(const char *file, int line, const char *format, ...)
60{
61 va_list args;
62
63 if (format[0] == '<' && format[1] >= '0' && format[1] <= '9' && format[2] == '>') {
64 char tmp[] = "<0>";
65 tmp[1] = format[1];
66 printk("%sALSA %s:%d: ", tmp, file, line);
67 format += 3;
68 } else {
69 printk(KERN_DEBUG "ALSA %s:%d: ", file, line);
70 }
71 va_start(args, format);
72 vprintk(format, args);
73 va_end(args);
74
75}
76#endif
diff --git a/sound/core/oss/Makefile b/sound/core/oss/Makefile
new file mode 100644
index 000000000000..e6d5a045ba27
--- /dev/null
+++ b/sound/core/oss/Makefile
@@ -0,0 +1,12 @@
1#
2# Makefile for ALSA
3# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-mixer-oss-objs := mixer_oss.o
7
8snd-pcm-oss-objs := pcm_oss.o pcm_plugin.o \
9 io.o copy.o linear.o mulaw.o route.o rate.o
10
11obj-$(CONFIG_SND_MIXER_OSS) += snd-mixer-oss.o
12obj-$(CONFIG_SND_PCM_OSS) += snd-pcm-oss.o
diff --git a/sound/core/oss/copy.c b/sound/core/oss/copy.c
new file mode 100644
index 000000000000..edecbe7417bd
--- /dev/null
+++ b/sound/core/oss/copy.c
@@ -0,0 +1,87 @@
1/*
2 * Linear conversion Plug-In
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; 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/time.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include "pcm_plugin.h"
27
28static snd_pcm_sframes_t copy_transfer(snd_pcm_plugin_t *plugin,
29 const snd_pcm_plugin_channel_t *src_channels,
30 snd_pcm_plugin_channel_t *dst_channels,
31 snd_pcm_uframes_t frames)
32{
33 unsigned int channel;
34 unsigned int nchannels;
35
36 snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
37 if (frames == 0)
38 return 0;
39 nchannels = plugin->src_format.channels;
40 for (channel = 0; channel < nchannels; channel++) {
41 snd_assert(src_channels->area.first % 8 == 0 &&
42 src_channels->area.step % 8 == 0,
43 return -ENXIO);
44 snd_assert(dst_channels->area.first % 8 == 0 &&
45 dst_channels->area.step % 8 == 0,
46 return -ENXIO);
47 if (!src_channels->enabled) {
48 if (dst_channels->wanted)
49 snd_pcm_area_silence(&dst_channels->area, 0, frames, plugin->dst_format.format);
50 dst_channels->enabled = 0;
51 continue;
52 }
53 dst_channels->enabled = 1;
54 snd_pcm_area_copy(&src_channels->area, 0, &dst_channels->area, 0, frames, plugin->src_format.format);
55 src_channels++;
56 dst_channels++;
57 }
58 return frames;
59}
60
61int snd_pcm_plugin_build_copy(snd_pcm_plug_t *plug,
62 snd_pcm_plugin_format_t *src_format,
63 snd_pcm_plugin_format_t *dst_format,
64 snd_pcm_plugin_t **r_plugin)
65{
66 int err;
67 snd_pcm_plugin_t *plugin;
68 int width;
69
70 snd_assert(r_plugin != NULL, return -ENXIO);
71 *r_plugin = NULL;
72
73 snd_assert(src_format->format == dst_format->format, return -ENXIO);
74 snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
75 snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
76
77 width = snd_pcm_format_physical_width(src_format->format);
78 snd_assert(width > 0, return -ENXIO);
79
80 err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format,
81 0, &plugin);
82 if (err < 0)
83 return err;
84 plugin->transfer = copy_transfer;
85 *r_plugin = plugin;
86 return 0;
87}
diff --git a/sound/core/oss/io.c b/sound/core/oss/io.c
new file mode 100644
index 000000000000..bb1c99a5b734
--- /dev/null
+++ b/sound/core/oss/io.c
@@ -0,0 +1,134 @@
1/*
2 * PCM I/O Plug-In Interface
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; 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/time.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include "pcm_plugin.h"
28
29#define pcm_write(plug,buf,count) snd_pcm_oss_write3(plug,buf,count,1)
30#define pcm_writev(plug,vec,count) snd_pcm_oss_writev3(plug,vec,count,1)
31#define pcm_read(plug,buf,count) snd_pcm_oss_read3(plug,buf,count,1)
32#define pcm_readv(plug,vec,count) snd_pcm_oss_readv3(plug,vec,count,1)
33
34/*
35 * Basic io plugin
36 */
37
38static snd_pcm_sframes_t io_playback_transfer(snd_pcm_plugin_t *plugin,
39 const snd_pcm_plugin_channel_t *src_channels,
40 snd_pcm_plugin_channel_t *dst_channels ATTRIBUTE_UNUSED,
41 snd_pcm_uframes_t frames)
42{
43 snd_assert(plugin != NULL, return -ENXIO);
44 snd_assert(src_channels != NULL, return -ENXIO);
45 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
46 return pcm_write(plugin->plug, src_channels->area.addr, frames);
47 } else {
48 int channel, channels = plugin->dst_format.channels;
49 void **bufs = (void**)plugin->extra_data;
50 snd_assert(bufs != NULL, return -ENXIO);
51 for (channel = 0; channel < channels; channel++) {
52 if (src_channels[channel].enabled)
53 bufs[channel] = src_channels[channel].area.addr;
54 else
55 bufs[channel] = NULL;
56 }
57 return pcm_writev(plugin->plug, bufs, frames);
58 }
59}
60
61static snd_pcm_sframes_t io_capture_transfer(snd_pcm_plugin_t *plugin,
62 const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
63 snd_pcm_plugin_channel_t *dst_channels,
64 snd_pcm_uframes_t frames)
65{
66 snd_assert(plugin != NULL, return -ENXIO);
67 snd_assert(dst_channels != NULL, return -ENXIO);
68 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
69 return pcm_read(plugin->plug, dst_channels->area.addr, frames);
70 } else {
71 int channel, channels = plugin->dst_format.channels;
72 void **bufs = (void**)plugin->extra_data;
73 snd_assert(bufs != NULL, return -ENXIO);
74 for (channel = 0; channel < channels; channel++) {
75 if (dst_channels[channel].enabled)
76 bufs[channel] = dst_channels[channel].area.addr;
77 else
78 bufs[channel] = NULL;
79 }
80 return pcm_readv(plugin->plug, bufs, frames);
81 }
82 return 0;
83}
84
85static snd_pcm_sframes_t io_src_channels(snd_pcm_plugin_t *plugin,
86 snd_pcm_uframes_t frames,
87 snd_pcm_plugin_channel_t **channels)
88{
89 int err;
90 unsigned int channel;
91 snd_pcm_plugin_channel_t *v;
92 err = snd_pcm_plugin_client_channels(plugin, frames, &v);
93 if (err < 0)
94 return err;
95 *channels = v;
96 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
97 for (channel = 0; channel < plugin->src_format.channels; ++channel, ++v)
98 v->wanted = 1;
99 }
100 return frames;
101}
102
103int snd_pcm_plugin_build_io(snd_pcm_plug_t *plug,
104 snd_pcm_hw_params_t *params,
105 snd_pcm_plugin_t **r_plugin)
106{
107 int err;
108 snd_pcm_plugin_format_t format;
109 snd_pcm_plugin_t *plugin;
110
111 snd_assert(r_plugin != NULL, return -ENXIO);
112 *r_plugin = NULL;
113 snd_assert(plug != NULL && params != NULL, return -ENXIO);
114 format.format = params_format(params);
115 format.rate = params_rate(params);
116 format.channels = params_channels(params);
117 err = snd_pcm_plugin_build(plug, "I/O io",
118 &format, &format,
119 sizeof(void *) * format.channels,
120 &plugin);
121 if (err < 0)
122 return err;
123 plugin->access = params_access(params);
124 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
125 plugin->transfer = io_playback_transfer;
126 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED)
127 plugin->client_channels = io_src_channels;
128 } else {
129 plugin->transfer = io_capture_transfer;
130 }
131
132 *r_plugin = plugin;
133 return 0;
134}
diff --git a/sound/core/oss/linear.c b/sound/core/oss/linear.c
new file mode 100644
index 000000000000..12ed27a57b27
--- /dev/null
+++ b/sound/core/oss/linear.c
@@ -0,0 +1,158 @@
1/*
2 * Linear conversion Plug-In
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>,
4 * Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include "pcm_plugin.h"
28
29/*
30 * Basic linear conversion plugin
31 */
32
33typedef struct linear_private_data {
34 int conv;
35} linear_t;
36
37static void convert(snd_pcm_plugin_t *plugin,
38 const snd_pcm_plugin_channel_t *src_channels,
39 snd_pcm_plugin_channel_t *dst_channels,
40 snd_pcm_uframes_t frames)
41{
42#define CONV_LABELS
43#include "plugin_ops.h"
44#undef CONV_LABELS
45 linear_t *data = (linear_t *)plugin->extra_data;
46 void *conv = conv_labels[data->conv];
47 int channel;
48 int nchannels = plugin->src_format.channels;
49 for (channel = 0; channel < nchannels; ++channel) {
50 char *src;
51 char *dst;
52 int src_step, dst_step;
53 snd_pcm_uframes_t frames1;
54 if (!src_channels[channel].enabled) {
55 if (dst_channels[channel].wanted)
56 snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
57 dst_channels[channel].enabled = 0;
58 continue;
59 }
60 dst_channels[channel].enabled = 1;
61 src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
62 dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
63 src_step = src_channels[channel].area.step / 8;
64 dst_step = dst_channels[channel].area.step / 8;
65 frames1 = frames;
66 while (frames1-- > 0) {
67 goto *conv;
68#define CONV_END after
69#include "plugin_ops.h"
70#undef CONV_END
71 after:
72 src += src_step;
73 dst += dst_step;
74 }
75 }
76}
77
78static snd_pcm_sframes_t linear_transfer(snd_pcm_plugin_t *plugin,
79 const snd_pcm_plugin_channel_t *src_channels,
80 snd_pcm_plugin_channel_t *dst_channels,
81 snd_pcm_uframes_t frames)
82{
83 linear_t *data;
84
85 snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
86 data = (linear_t *)plugin->extra_data;
87 if (frames == 0)
88 return 0;
89#ifdef CONFIG_SND_DEBUG
90 {
91 unsigned int channel;
92 for (channel = 0; channel < plugin->src_format.channels; channel++) {
93 snd_assert(src_channels[channel].area.first % 8 == 0 &&
94 src_channels[channel].area.step % 8 == 0,
95 return -ENXIO);
96 snd_assert(dst_channels[channel].area.first % 8 == 0 &&
97 dst_channels[channel].area.step % 8 == 0,
98 return -ENXIO);
99 }
100 }
101#endif
102 convert(plugin, src_channels, dst_channels, frames);
103 return frames;
104}
105
106int conv_index(int src_format, int dst_format)
107{
108 int src_endian, dst_endian, sign, src_width, dst_width;
109
110 sign = (snd_pcm_format_signed(src_format) !=
111 snd_pcm_format_signed(dst_format));
112#ifdef SNDRV_LITTLE_ENDIAN
113 src_endian = snd_pcm_format_big_endian(src_format);
114 dst_endian = snd_pcm_format_big_endian(dst_format);
115#else
116 src_endian = snd_pcm_format_little_endian(src_format);
117 dst_endian = snd_pcm_format_little_endian(dst_format);
118#endif
119
120 if (src_endian < 0)
121 src_endian = 0;
122 if (dst_endian < 0)
123 dst_endian = 0;
124
125 src_width = snd_pcm_format_width(src_format) / 8 - 1;
126 dst_width = snd_pcm_format_width(dst_format) / 8 - 1;
127
128 return src_width * 32 + src_endian * 16 + sign * 8 + dst_width * 2 + dst_endian;
129}
130
131int snd_pcm_plugin_build_linear(snd_pcm_plug_t *plug,
132 snd_pcm_plugin_format_t *src_format,
133 snd_pcm_plugin_format_t *dst_format,
134 snd_pcm_plugin_t **r_plugin)
135{
136 int err;
137 struct linear_private_data *data;
138 snd_pcm_plugin_t *plugin;
139
140 snd_assert(r_plugin != NULL, return -ENXIO);
141 *r_plugin = NULL;
142
143 snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
144 snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
145 snd_assert(snd_pcm_format_linear(src_format->format) &&
146 snd_pcm_format_linear(dst_format->format), return -ENXIO);
147
148 err = snd_pcm_plugin_build(plug, "linear format conversion",
149 src_format, dst_format,
150 sizeof(linear_t), &plugin);
151 if (err < 0)
152 return err;
153 data = (linear_t *)plugin->extra_data;
154 data->conv = conv_index(src_format->format, dst_format->format);
155 plugin->transfer = linear_transfer;
156 *r_plugin = plugin;
157 return 0;
158}
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
new file mode 100644
index 000000000000..98ed9a9f0da6
--- /dev/null
+++ b/sound/core/oss/mixer_oss.c
@@ -0,0 +1,1340 @@
1/*
2 * OSS emulation layer for the mixer interface
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/smp_lock.h>
25#include <linux/slab.h>
26#include <linux/time.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
36MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
37MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
38MODULE_LICENSE("GPL");
39MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
40
41static int snd_mixer_oss_open(struct inode *inode, struct file *file)
42{
43 int cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
44 snd_card_t *card;
45 snd_mixer_oss_file_t *fmixer;
46 int err;
47
48 if ((card = snd_cards[cardnum]) == NULL)
49 return -ENODEV;
50 if (card->mixer_oss == NULL)
51 return -ENODEV;
52 err = snd_card_file_add(card, file);
53 if (err < 0)
54 return err;
55 fmixer = kcalloc(1, sizeof(*fmixer), GFP_KERNEL);
56 if (fmixer == NULL) {
57 snd_card_file_remove(card, file);
58 return -ENOMEM;
59 }
60 fmixer->card = card;
61 fmixer->mixer = card->mixer_oss;
62 file->private_data = fmixer;
63 if (!try_module_get(card->module)) {
64 kfree(fmixer);
65 snd_card_file_remove(card, file);
66 return -EFAULT;
67 }
68 return 0;
69}
70
71static int snd_mixer_oss_release(struct inode *inode, struct file *file)
72{
73 snd_mixer_oss_file_t *fmixer;
74
75 if (file->private_data) {
76 fmixer = (snd_mixer_oss_file_t *) file->private_data;
77 module_put(fmixer->card->module);
78 snd_card_file_remove(fmixer->card, file);
79 kfree(fmixer);
80 }
81 return 0;
82}
83
84static int snd_mixer_oss_info(snd_mixer_oss_file_t *fmixer,
85 mixer_info __user *_info)
86{
87 snd_card_t *card = fmixer->card;
88 snd_mixer_oss_t *mixer = fmixer->mixer;
89 struct mixer_info info;
90
91 memset(&info, 0, sizeof(info));
92 strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
93 strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
94 info.modify_counter = card->mixer_oss_change_count;
95 if (copy_to_user(_info, &info, sizeof(info)))
96 return -EFAULT;
97 return 0;
98}
99
100static int snd_mixer_oss_info_obsolete(snd_mixer_oss_file_t *fmixer,
101 _old_mixer_info __user *_info)
102{
103 snd_card_t *card = fmixer->card;
104 snd_mixer_oss_t *mixer = fmixer->mixer;
105 _old_mixer_info info;
106
107 memset(&info, 0, sizeof(info));
108 strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
109 strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
110 if (copy_to_user(_info, &info, sizeof(info)))
111 return -EFAULT;
112 return 0;
113}
114
115static int snd_mixer_oss_caps(snd_mixer_oss_file_t *fmixer)
116{
117 snd_mixer_oss_t *mixer = fmixer->mixer;
118 int result = 0;
119
120 if (mixer == NULL)
121 return -EIO;
122 if (mixer->get_recsrc && mixer->put_recsrc)
123 result |= SOUND_CAP_EXCL_INPUT;
124 return result;
125}
126
127static int snd_mixer_oss_devmask(snd_mixer_oss_file_t *fmixer)
128{
129 snd_mixer_oss_t *mixer = fmixer->mixer;
130 snd_mixer_oss_slot_t *pslot;
131 int result = 0, chn;
132
133 if (mixer == NULL)
134 return -EIO;
135 for (chn = 0; chn < 31; chn++) {
136 pslot = &mixer->slots[chn];
137 if (pslot->put_volume || pslot->put_recsrc)
138 result |= 1 << chn;
139 }
140 return result;
141}
142
143static int snd_mixer_oss_stereodevs(snd_mixer_oss_file_t *fmixer)
144{
145 snd_mixer_oss_t *mixer = fmixer->mixer;
146 snd_mixer_oss_slot_t *pslot;
147 int result = 0, chn;
148
149 if (mixer == NULL)
150 return -EIO;
151 for (chn = 0; chn < 31; chn++) {
152 pslot = &mixer->slots[chn];
153 if (pslot->put_volume && pslot->stereo)
154 result |= 1 << chn;
155 }
156 return result;
157}
158
159static int snd_mixer_oss_recmask(snd_mixer_oss_file_t *fmixer)
160{
161 snd_mixer_oss_t *mixer = fmixer->mixer;
162 int result = 0;
163
164 if (mixer == NULL)
165 return -EIO;
166 if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
167 result = mixer->mask_recsrc;
168 } else {
169 snd_mixer_oss_slot_t *pslot;
170 int chn;
171 for (chn = 0; chn < 31; chn++) {
172 pslot = &mixer->slots[chn];
173 if (pslot->put_recsrc)
174 result |= 1 << chn;
175 }
176 }
177 return result;
178}
179
180static int snd_mixer_oss_get_recsrc(snd_mixer_oss_file_t *fmixer)
181{
182 snd_mixer_oss_t *mixer = fmixer->mixer;
183 int result = 0;
184
185 if (mixer == NULL)
186 return -EIO;
187 if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
188 int err;
189 if ((err = mixer->get_recsrc(fmixer, &result)) < 0)
190 return err;
191 result = 1 << result;
192 } else {
193 snd_mixer_oss_slot_t *pslot;
194 int chn;
195 for (chn = 0; chn < 31; chn++) {
196 pslot = &mixer->slots[chn];
197 if (pslot->get_recsrc) {
198 int active = 0;
199 pslot->get_recsrc(fmixer, pslot, &active);
200 if (active)
201 result |= 1 << chn;
202 }
203 }
204 }
205 return mixer->oss_recsrc = result;
206}
207
208static int snd_mixer_oss_set_recsrc(snd_mixer_oss_file_t *fmixer, int recsrc)
209{
210 snd_mixer_oss_t *mixer = fmixer->mixer;
211 snd_mixer_oss_slot_t *pslot;
212 int chn, active;
213 int result = 0;
214
215 if (mixer == NULL)
216 return -EIO;
217 if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
218 if (recsrc & ~mixer->oss_recsrc)
219 recsrc &= ~mixer->oss_recsrc;
220 mixer->put_recsrc(fmixer, ffz(~recsrc));
221 mixer->get_recsrc(fmixer, &result);
222 result = 1 << result;
223 }
224 for (chn = 0; chn < 31; chn++) {
225 pslot = &mixer->slots[chn];
226 if (pslot->put_recsrc) {
227 active = (recsrc & (1 << chn)) ? 1 : 0;
228 pslot->put_recsrc(fmixer, pslot, active);
229 }
230 }
231 if (! result) {
232 for (chn = 0; chn < 31; chn++) {
233 pslot = &mixer->slots[chn];
234 if (pslot->get_recsrc) {
235 active = 0;
236 pslot->get_recsrc(fmixer, pslot, &active);
237 if (active)
238 result |= 1 << chn;
239 }
240 }
241 }
242 return result;
243}
244
245static int snd_mixer_oss_get_volume(snd_mixer_oss_file_t *fmixer, int slot)
246{
247 snd_mixer_oss_t *mixer = fmixer->mixer;
248 snd_mixer_oss_slot_t *pslot;
249 int result = 0, left, right;
250
251 if (mixer == NULL || slot > 30)
252 return -EIO;
253 pslot = &mixer->slots[slot];
254 left = pslot->volume[0];
255 right = pslot->volume[1];
256 if (pslot->get_volume)
257 result = pslot->get_volume(fmixer, pslot, &left, &right);
258 if (!pslot->stereo)
259 right = left;
260 snd_assert(left >= 0 && left <= 100, return -EIO);
261 snd_assert(right >= 0 && right <= 100, return -EIO);
262 if (result >= 0) {
263 pslot->volume[0] = left;
264 pslot->volume[1] = right;
265 result = (left & 0xff) | ((right & 0xff) << 8);
266 }
267 return result;
268}
269
270static int snd_mixer_oss_set_volume(snd_mixer_oss_file_t *fmixer,
271 int slot, int volume)
272{
273 snd_mixer_oss_t *mixer = fmixer->mixer;
274 snd_mixer_oss_slot_t *pslot;
275 int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
276
277 if (mixer == NULL || slot > 30)
278 return -EIO;
279 pslot = &mixer->slots[slot];
280 if (left > 100)
281 left = 100;
282 if (right > 100)
283 right = 100;
284 if (!pslot->stereo)
285 right = left;
286 if (pslot->put_volume)
287 result = pslot->put_volume(fmixer, pslot, left, right);
288 if (result < 0)
289 return result;
290 pslot->volume[0] = left;
291 pslot->volume[1] = right;
292 return (left & 0xff) | ((right & 0xff) << 8);
293}
294
295static int snd_mixer_oss_ioctl1(snd_mixer_oss_file_t *fmixer, unsigned int cmd, unsigned long arg)
296{
297 void __user *argp = (void __user *)arg;
298 int __user *p = argp;
299 int tmp;
300
301 snd_assert(fmixer != NULL, return -ENXIO);
302 if (((cmd >> 8) & 0xff) == 'M') {
303 switch (cmd) {
304 case SOUND_MIXER_INFO:
305 return snd_mixer_oss_info(fmixer, argp);
306 case SOUND_OLD_MIXER_INFO:
307 return snd_mixer_oss_info_obsolete(fmixer, argp);
308 case SOUND_MIXER_WRITE_RECSRC:
309 if (get_user(tmp, p))
310 return -EFAULT;
311 tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
312 if (tmp < 0)
313 return tmp;
314 return put_user(tmp, p);
315 case OSS_GETVERSION:
316 return put_user(SNDRV_OSS_VERSION, p);
317 case OSS_ALSAEMULVER:
318 return put_user(1, p);
319 case SOUND_MIXER_READ_DEVMASK:
320 tmp = snd_mixer_oss_devmask(fmixer);
321 if (tmp < 0)
322 return tmp;
323 return put_user(tmp, p);
324 case SOUND_MIXER_READ_STEREODEVS:
325 tmp = snd_mixer_oss_stereodevs(fmixer);
326 if (tmp < 0)
327 return tmp;
328 return put_user(tmp, p);
329 case SOUND_MIXER_READ_RECMASK:
330 tmp = snd_mixer_oss_recmask(fmixer);
331 if (tmp < 0)
332 return tmp;
333 return put_user(tmp, p);
334 case SOUND_MIXER_READ_CAPS:
335 tmp = snd_mixer_oss_caps(fmixer);
336 if (tmp < 0)
337 return tmp;
338 return put_user(tmp, p);
339 case SOUND_MIXER_READ_RECSRC:
340 tmp = snd_mixer_oss_get_recsrc(fmixer);
341 if (tmp < 0)
342 return tmp;
343 return put_user(tmp, p);
344 }
345 }
346 if (cmd & SIOC_IN) {
347 if (get_user(tmp, p))
348 return -EFAULT;
349 tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
350 if (tmp < 0)
351 return tmp;
352 return put_user(tmp, p);
353 } else if (cmd & SIOC_OUT) {
354 tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
355 if (tmp < 0)
356 return tmp;
357 return put_user(tmp, p);
358 }
359 return -ENXIO;
360}
361
362static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
363{
364 return snd_mixer_oss_ioctl1((snd_mixer_oss_file_t *) file->private_data, cmd, arg);
365}
366
367int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg)
368{
369 snd_mixer_oss_file_t fmixer;
370
371 snd_assert(card != NULL, return -ENXIO);
372 if (card->mixer_oss == NULL)
373 return -ENXIO;
374 memset(&fmixer, 0, sizeof(fmixer));
375 fmixer.card = card;
376 fmixer.mixer = card->mixer_oss;
377 return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
378}
379
380#ifdef CONFIG_COMPAT
381/* all compatible */
382#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl
383#else
384#define snd_mixer_oss_ioctl_compat NULL
385#endif
386
387/*
388 * REGISTRATION PART
389 */
390
391static struct file_operations snd_mixer_oss_f_ops =
392{
393 .owner = THIS_MODULE,
394 .open = snd_mixer_oss_open,
395 .release = snd_mixer_oss_release,
396 .unlocked_ioctl = snd_mixer_oss_ioctl,
397 .compat_ioctl = snd_mixer_oss_ioctl_compat,
398};
399
400static snd_minor_t snd_mixer_oss_reg =
401{
402 .comment = "mixer",
403 .f_ops = &snd_mixer_oss_f_ops,
404};
405
406/*
407 * utilities
408 */
409
410static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax)
411{
412 long orange = omax - omin, nrange = nmax - nmin;
413
414 if (orange == 0)
415 return 0;
416 return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
417}
418
419/* convert from alsa native to oss values (0-100) */
420static long snd_mixer_oss_conv1(long val, long min, long max, int *old)
421{
422 if (val == snd_mixer_oss_conv(*old, 0, 100, min, max))
423 return *old;
424 return snd_mixer_oss_conv(val, min, max, 0, 100);
425}
426
427/* convert from oss to alsa native values */
428static long snd_mixer_oss_conv2(long val, long min, long max)
429{
430 return snd_mixer_oss_conv(val, 0, 100, min, max);
431}
432
433#if 0
434static void snd_mixer_oss_recsrce_set(snd_card_t *card, int slot)
435{
436 snd_mixer_oss_t *mixer = card->mixer_oss;
437 if (mixer)
438 mixer->mask_recsrc |= 1 << slot;
439}
440
441static int snd_mixer_oss_recsrce_get(snd_card_t *card, int slot)
442{
443 snd_mixer_oss_t *mixer = card->mixer_oss;
444 if (mixer && (mixer->mask_recsrc & (1 << slot)))
445 return 1;
446 return 0;
447}
448#endif
449
450#define SNDRV_MIXER_OSS_SIGNATURE 0x65999250
451
452#define SNDRV_MIXER_OSS_ITEM_GLOBAL 0
453#define SNDRV_MIXER_OSS_ITEM_GSWITCH 1
454#define SNDRV_MIXER_OSS_ITEM_GROUTE 2
455#define SNDRV_MIXER_OSS_ITEM_GVOLUME 3
456#define SNDRV_MIXER_OSS_ITEM_PSWITCH 4
457#define SNDRV_MIXER_OSS_ITEM_PROUTE 5
458#define SNDRV_MIXER_OSS_ITEM_PVOLUME 6
459#define SNDRV_MIXER_OSS_ITEM_CSWITCH 7
460#define SNDRV_MIXER_OSS_ITEM_CROUTE 8
461#define SNDRV_MIXER_OSS_ITEM_CVOLUME 9
462#define SNDRV_MIXER_OSS_ITEM_CAPTURE 10
463
464#define SNDRV_MIXER_OSS_ITEM_COUNT 11
465
466#define SNDRV_MIXER_OSS_PRESENT_GLOBAL (1<<0)
467#define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1)
468#define SNDRV_MIXER_OSS_PRESENT_GROUTE (1<<2)
469#define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3)
470#define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4)
471#define SNDRV_MIXER_OSS_PRESENT_PROUTE (1<<5)
472#define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6)
473#define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7)
474#define SNDRV_MIXER_OSS_PRESENT_CROUTE (1<<8)
475#define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9)
476#define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10)
477
478struct slot {
479 unsigned int signature;
480 unsigned int present;
481 unsigned int channels;
482 unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
483 unsigned int capture_item;
484 struct snd_mixer_oss_assign_table *assigned;
485 unsigned int allocated: 1;
486};
487
488#define ID_UNKNOWN ((unsigned int)-1)
489
490static snd_kcontrol_t *snd_mixer_oss_test_id(snd_mixer_oss_t *mixer, const char *name, int index)
491{
492 snd_card_t * card = mixer->card;
493 snd_ctl_elem_id_t id;
494
495 memset(&id, 0, sizeof(id));
496 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
497 strcpy(id.name, name);
498 id.index = index;
499 return snd_ctl_find_id(card, &id);
500}
501
502static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer,
503 snd_mixer_oss_slot_t *pslot,
504 unsigned int numid,
505 int *left, int *right)
506{
507 snd_ctl_elem_info_t *uinfo;
508 snd_ctl_elem_value_t *uctl;
509 snd_kcontrol_t *kctl;
510 snd_card_t *card = fmixer->card;
511
512 if (numid == ID_UNKNOWN)
513 return;
514 down_read(&card->controls_rwsem);
515 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
516 up_read(&card->controls_rwsem);
517 return;
518 }
519 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL);
520 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL);
521 if (uinfo == NULL || uctl == NULL)
522 goto __unalloc;
523 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
524 snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
525 snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc);
526 *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
527 if (uinfo->count > 1)
528 *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
529 __unalloc:
530 up_read(&card->controls_rwsem);
531 kfree(uctl);
532 kfree(uinfo);
533}
534
535static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer,
536 snd_mixer_oss_slot_t *pslot,
537 unsigned int numid,
538 int *left, int *right,
539 int route)
540{
541 snd_ctl_elem_info_t *uinfo;
542 snd_ctl_elem_value_t *uctl;
543 snd_kcontrol_t *kctl;
544 snd_card_t *card = fmixer->card;
545
546 if (numid == ID_UNKNOWN)
547 return;
548 down_read(&card->controls_rwsem);
549 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
550 up_read(&card->controls_rwsem);
551 return;
552 }
553 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL);
554 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL);
555 if (uinfo == NULL || uctl == NULL)
556 goto __unalloc;
557 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
558 snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
559 if (!uctl->value.integer.value[0]) {
560 *left = 0;
561 if (uinfo->count == 1)
562 *right = 0;
563 }
564 if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
565 *right = 0;
566 __unalloc:
567 up_read(&card->controls_rwsem);
568 kfree(uctl);
569 kfree(uinfo);
570}
571
572static int snd_mixer_oss_get_volume1(snd_mixer_oss_file_t *fmixer,
573 snd_mixer_oss_slot_t *pslot,
574 int *left, int *right)
575{
576 struct slot *slot = (struct slot *)pslot->private_data;
577
578 *left = *right = 100;
579 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
580 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
581 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
582 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
583 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
584 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
585 }
586 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
587 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
588 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
589 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
590 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
591 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
592 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
593 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
594 }
595 return 0;
596}
597
598static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer,
599 snd_mixer_oss_slot_t *pslot,
600 unsigned int numid,
601 int left, int right)
602{
603 snd_ctl_elem_info_t *uinfo;
604 snd_ctl_elem_value_t *uctl;
605 snd_kcontrol_t *kctl;
606 snd_card_t *card = fmixer->card;
607 int res;
608
609 if (numid == ID_UNKNOWN)
610 return;
611 down_read(&card->controls_rwsem);
612 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL)
613 return;
614 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL);
615 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL);
616 if (uinfo == NULL || uctl == NULL)
617 goto __unalloc;
618 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
619 snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, goto __unalloc);
620 uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
621 if (uinfo->count > 1)
622 uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
623 snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc);
624 if (res > 0)
625 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
626 __unalloc:
627 up_read(&card->controls_rwsem);
628 kfree(uctl);
629 kfree(uinfo);
630}
631
632static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer,
633 snd_mixer_oss_slot_t *pslot,
634 unsigned int numid,
635 int left, int right,
636 int route)
637{
638 snd_ctl_elem_info_t *uinfo;
639 snd_ctl_elem_value_t *uctl;
640 snd_kcontrol_t *kctl;
641 snd_card_t *card = fmixer->card;
642 int res;
643
644 if (numid == ID_UNKNOWN)
645 return;
646 down_read(&card->controls_rwsem);
647 if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
648 up_read(&fmixer->card->controls_rwsem);
649 return;
650 }
651 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL);
652 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL);
653 if (uinfo == NULL || uctl == NULL)
654 goto __unalloc;
655 snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
656 if (uinfo->count > 1) {
657 uctl->value.integer.value[0] = left > 0 ? 1 : 0;
658 uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
659 if (route) {
660 uctl->value.integer.value[1] =
661 uctl->value.integer.value[2] = 0;
662 }
663 } else {
664 uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
665 }
666 snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc);
667 if (res > 0)
668 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
669 __unalloc:
670 up_read(&card->controls_rwsem);
671 kfree(uctl);
672 kfree(uinfo);
673}
674
675static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer,
676 snd_mixer_oss_slot_t *pslot,
677 int left, int right)
678{
679 struct slot *slot = (struct slot *)pslot->private_data;
680
681 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
682 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
683 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
684 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
685 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
686 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
687 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
688 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
689 }
690 if (left || right) {
691 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
692 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
693 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
694 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
695 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
696 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
697 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
698 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
699 } else {
700 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
701 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
702 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
703 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
704 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
705 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
706 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
707 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
708 }
709 }
710 return 0;
711}
712
713static int snd_mixer_oss_get_recsrc1_sw(snd_mixer_oss_file_t *fmixer,
714 snd_mixer_oss_slot_t *pslot,
715 int *active)
716{
717 struct slot *slot = (struct slot *)pslot->private_data;
718 int left, right;
719
720 left = right = 1;
721 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0);
722 *active = (left || right) ? 1 : 0;
723 return 0;
724}
725
726static int snd_mixer_oss_get_recsrc1_route(snd_mixer_oss_file_t *fmixer,
727 snd_mixer_oss_slot_t *pslot,
728 int *active)
729{
730 struct slot *slot = (struct slot *)pslot->private_data;
731 int left, right;
732
733 left = right = 1;
734 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1);
735 *active = (left || right) ? 1 : 0;
736 return 0;
737}
738
739static int snd_mixer_oss_put_recsrc1_sw(snd_mixer_oss_file_t *fmixer,
740 snd_mixer_oss_slot_t *pslot,
741 int active)
742{
743 struct slot *slot = (struct slot *)pslot->private_data;
744
745 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
746 return 0;
747}
748
749static int snd_mixer_oss_put_recsrc1_route(snd_mixer_oss_file_t *fmixer,
750 snd_mixer_oss_slot_t *pslot,
751 int active)
752{
753 struct slot *slot = (struct slot *)pslot->private_data;
754
755 snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
756 return 0;
757}
758
759static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int *active_index)
760{
761 snd_card_t *card = fmixer->card;
762 snd_mixer_oss_t *mixer = fmixer->mixer;
763 snd_kcontrol_t *kctl;
764 snd_mixer_oss_slot_t *pslot;
765 struct slot *slot;
766 snd_ctl_elem_info_t *uinfo;
767 snd_ctl_elem_value_t *uctl;
768 int err, idx;
769
770 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL);
771 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL);
772 if (uinfo == NULL || uctl == NULL) {
773 err = -ENOMEM;
774 goto __unlock;
775 }
776 down_read(&card->controls_rwsem);
777 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
778 snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock);
779 snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock);
780 snd_runtime_check(!(err = kctl->get(kctl, uctl)), goto __unlock);
781 for (idx = 0; idx < 32; idx++) {
782 if (!(mixer->mask_recsrc & (1 << idx)))
783 continue;
784 pslot = &mixer->slots[idx];
785 slot = (struct slot *)pslot->private_data;
786 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
787 continue;
788 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
789 continue;
790 if (slot->capture_item == uctl->value.enumerated.item[0]) {
791 *active_index = idx;
792 break;
793 }
794 }
795 err = 0;
796 __unlock:
797 up_read(&card->controls_rwsem);
798 kfree(uctl);
799 kfree(uinfo);
800 return err;
801}
802
803static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int active_index)
804{
805 snd_card_t *card = fmixer->card;
806 snd_mixer_oss_t *mixer = fmixer->mixer;
807 snd_kcontrol_t *kctl;
808 snd_mixer_oss_slot_t *pslot;
809 struct slot *slot = NULL;
810 snd_ctl_elem_info_t *uinfo;
811 snd_ctl_elem_value_t *uctl;
812 int err;
813 unsigned int idx;
814
815 uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL);
816 uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL);
817 if (uinfo == NULL || uctl == NULL) {
818 err = -ENOMEM;
819 goto __unlock;
820 }
821 down_read(&card->controls_rwsem);
822 kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
823 snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock);
824 snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock);
825 for (idx = 0; idx < 32; idx++) {
826 if (!(mixer->mask_recsrc & (1 << idx)))
827 continue;
828 pslot = &mixer->slots[idx];
829 slot = (struct slot *)pslot->private_data;
830 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
831 continue;
832 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
833 continue;
834 if (idx == active_index)
835 break;
836 slot = NULL;
837 }
838 snd_runtime_check(slot != NULL, goto __unlock);
839 for (idx = 0; idx < uinfo->count; idx++)
840 uctl->value.enumerated.item[idx] = slot->capture_item;
841 snd_runtime_check((err = kctl->put(kctl, uctl)) >= 0, );
842 if (err > 0)
843 snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
844 err = 0;
845 __unlock:
846 up_read(&card->controls_rwsem);
847 kfree(uctl);
848 kfree(uinfo);
849 return err;
850}
851
852struct snd_mixer_oss_assign_table {
853 int oss_id;
854 const char *name;
855 int index;
856};
857
858static int snd_mixer_oss_build_test(snd_mixer_oss_t *mixer, struct slot *slot, const char *name, int index, int item)
859{
860 snd_ctl_elem_info_t *info;
861 snd_kcontrol_t *kcontrol;
862 snd_card_t *card = mixer->card;
863 int err;
864
865 down_read(&card->controls_rwsem);
866 kcontrol = snd_mixer_oss_test_id(mixer, name, index);
867 if (kcontrol == NULL) {
868 up_read(&card->controls_rwsem);
869 return 0;
870 }
871 info = kmalloc(sizeof(*info), GFP_KERNEL);
872 if (! info) {
873 up_read(&card->controls_rwsem);
874 return -ENOMEM;
875 }
876 if ((err = kcontrol->info(kcontrol, info)) < 0) {
877 up_read(&card->controls_rwsem);
878 kfree(info);
879 return err;
880 }
881 slot->numid[item] = kcontrol->id.numid;
882 up_read(&card->controls_rwsem);
883 if (info->count > slot->channels)
884 slot->channels = info->count;
885 slot->present |= 1 << item;
886 kfree(info);
887 return 0;
888}
889
890static void snd_mixer_oss_slot_free(snd_mixer_oss_slot_t *chn)
891{
892 struct slot *p = (struct slot *)chn->private_data;
893 if (p) {
894 if (p->allocated && p->assigned) {
895 kfree(p->assigned->name);
896 kfree(p->assigned);
897 }
898 kfree(p);
899 }
900}
901
902static void mixer_slot_clear(snd_mixer_oss_slot_t *rslot)
903{
904 int idx = rslot->number; /* remember this */
905 if (rslot->private_free)
906 rslot->private_free(rslot);
907 memset(rslot, 0, sizeof(*rslot));
908 rslot->number = idx;
909}
910
911/*
912 * build an OSS mixer element.
913 * ptr_allocated means the entry is dynamically allocated (change via proc file).
914 * when replace_old = 1, the old entry is replaced with the new one.
915 */
916static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old)
917{
918 struct slot slot;
919 struct slot *pslot;
920 snd_kcontrol_t *kctl;
921 snd_mixer_oss_slot_t *rslot;
922 char str[64];
923
924 /* check if already assigned */
925 if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
926 return 0;
927
928 memset(&slot, 0, sizeof(slot));
929 memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
930 if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index,
931 SNDRV_MIXER_OSS_ITEM_GLOBAL))
932 return 0;
933 sprintf(str, "%s Switch", ptr->name);
934 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
935 SNDRV_MIXER_OSS_ITEM_GSWITCH))
936 return 0;
937 sprintf(str, "%s Route", ptr->name);
938 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
939 SNDRV_MIXER_OSS_ITEM_GROUTE))
940 return 0;
941 sprintf(str, "%s Volume", ptr->name);
942 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
943 SNDRV_MIXER_OSS_ITEM_GVOLUME))
944 return 0;
945 sprintf(str, "%s Playback Switch", ptr->name);
946 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
947 SNDRV_MIXER_OSS_ITEM_PSWITCH))
948 return 0;
949 sprintf(str, "%s Playback Route", ptr->name);
950 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
951 SNDRV_MIXER_OSS_ITEM_PROUTE))
952 return 0;
953 sprintf(str, "%s Playback Volume", ptr->name);
954 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
955 SNDRV_MIXER_OSS_ITEM_PVOLUME))
956 return 0;
957 sprintf(str, "%s Capture Switch", ptr->name);
958 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
959 SNDRV_MIXER_OSS_ITEM_CSWITCH))
960 return 0;
961 sprintf(str, "%s Capture Route", ptr->name);
962 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
963 SNDRV_MIXER_OSS_ITEM_CROUTE))
964 return 0;
965 sprintf(str, "%s Capture Volume", ptr->name);
966 if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
967 SNDRV_MIXER_OSS_ITEM_CVOLUME))
968 return 0;
969 down_read(&mixer->card->controls_rwsem);
970 if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
971 snd_ctl_elem_info_t *uinfo;
972
973 uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
974 if (! uinfo) {
975 up_read(&mixer->card->controls_rwsem);
976 return -ENOMEM;
977 }
978
979 memset(uinfo, 0, sizeof(*uinfo));
980 if (kctl->info(kctl, uinfo)) {
981 up_read(&mixer->card->controls_rwsem);
982 return 0;
983 }
984 strcpy(str, ptr->name);
985 if (!strcmp(str, "Master"))
986 strcpy(str, "Mix");
987 if (!strcmp(str, "Master Mono"))
988 strcpy(str, "Mix Mono");
989 slot.capture_item = 0;
990 if (!strcmp(uinfo->value.enumerated.name, str)) {
991 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
992 } else {
993 for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
994 uinfo->value.enumerated.item = slot.capture_item;
995 if (kctl->info(kctl, uinfo)) {
996 up_read(&mixer->card->controls_rwsem);
997 return 0;
998 }
999 if (!strcmp(uinfo->value.enumerated.name, str)) {
1000 slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1001 break;
1002 }
1003 }
1004 }
1005 kfree(uinfo);
1006 }
1007 up_read(&mixer->card->controls_rwsem);
1008 if (slot.present != 0) {
1009 pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL);
1010 snd_runtime_check(pslot != NULL, return -ENOMEM);
1011 *pslot = slot;
1012 pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
1013 pslot->assigned = ptr;
1014 pslot->allocated = ptr_allocated;
1015 rslot = &mixer->slots[ptr->oss_id];
1016 mixer_slot_clear(rslot);
1017 rslot->stereo = slot.channels > 1 ? 1 : 0;
1018 rslot->get_volume = snd_mixer_oss_get_volume1;
1019 rslot->put_volume = snd_mixer_oss_put_volume1;
1020 /* note: ES18xx have both Capture Source and XX Capture Volume !!! */
1021 if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
1022 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw;
1023 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw;
1024 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
1025 rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route;
1026 rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route;
1027 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) {
1028 mixer->mask_recsrc |= 1 << ptr->oss_id;
1029 }
1030 rslot->private_data = pslot;
1031 rslot->private_free = snd_mixer_oss_slot_free;
1032 return 1;
1033 }
1034 return 0;
1035}
1036
1037/*
1038 */
1039#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
1040static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
1041 MIXER_VOL(VOLUME),
1042 MIXER_VOL(BASS),
1043 MIXER_VOL(TREBLE),
1044 MIXER_VOL(SYNTH),
1045 MIXER_VOL(PCM),
1046 MIXER_VOL(SPEAKER),
1047 MIXER_VOL(LINE),
1048 MIXER_VOL(MIC),
1049 MIXER_VOL(CD),
1050 MIXER_VOL(IMIX),
1051 MIXER_VOL(ALTPCM),
1052 MIXER_VOL(RECLEV),
1053 MIXER_VOL(IGAIN),
1054 MIXER_VOL(OGAIN),
1055 MIXER_VOL(LINE1),
1056 MIXER_VOL(LINE2),
1057 MIXER_VOL(LINE3),
1058 MIXER_VOL(DIGITAL1),
1059 MIXER_VOL(DIGITAL2),
1060 MIXER_VOL(DIGITAL3),
1061 MIXER_VOL(PHONEIN),
1062 MIXER_VOL(PHONEOUT),
1063 MIXER_VOL(VIDEO),
1064 MIXER_VOL(RADIO),
1065 MIXER_VOL(MONITOR),
1066};
1067
1068/*
1069 * /proc interface
1070 */
1071
1072static void snd_mixer_oss_proc_read(snd_info_entry_t *entry,
1073 snd_info_buffer_t * buffer)
1074{
1075 snd_mixer_oss_t *mixer = entry->private_data;
1076 int i;
1077
1078 down(&mixer->reg_mutex);
1079 for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
1080 struct slot *p;
1081
1082 if (! oss_mixer_names[i])
1083 continue;
1084 p = (struct slot *)mixer->slots[i].private_data;
1085 snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
1086 if (p && p->assigned)
1087 snd_iprintf(buffer, "\"%s\" %d\n",
1088 p->assigned->name,
1089 p->assigned->index);
1090 else
1091 snd_iprintf(buffer, "\"\" 0\n");
1092 }
1093 up(&mixer->reg_mutex);
1094}
1095
1096static void snd_mixer_oss_proc_write(snd_info_entry_t *entry,
1097 snd_info_buffer_t * buffer)
1098{
1099 snd_mixer_oss_t *mixer = entry->private_data;
1100 char line[128], str[32], idxstr[16], *cptr;
1101 int ch, idx;
1102 struct snd_mixer_oss_assign_table *tbl;
1103 struct slot *slot;
1104
1105 while (!snd_info_get_line(buffer, line, sizeof(line))) {
1106 cptr = snd_info_get_str(str, line, sizeof(str));
1107 for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
1108 if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
1109 break;
1110 if (ch >= SNDRV_OSS_MAX_MIXERS) {
1111 snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
1112 continue;
1113 }
1114 cptr = snd_info_get_str(str, cptr, sizeof(str));
1115 if (! *str) {
1116 /* remove the entry */
1117 down(&mixer->reg_mutex);
1118 mixer_slot_clear(&mixer->slots[ch]);
1119 up(&mixer->reg_mutex);
1120 continue;
1121 }
1122 snd_info_get_str(idxstr, cptr, sizeof(idxstr));
1123 idx = simple_strtoul(idxstr, NULL, 10);
1124 if (idx >= 0x4000) { /* too big */
1125 snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
1126 continue;
1127 }
1128 down(&mixer->reg_mutex);
1129 slot = (struct slot *)mixer->slots[ch].private_data;
1130 if (slot && slot->assigned &&
1131 slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
1132 /* not changed */
1133 goto __unlock;
1134 tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
1135 if (! tbl) {
1136 snd_printk(KERN_ERR "mixer_oss: no memory\n");
1137 goto __unlock;
1138 }
1139 tbl->oss_id = ch;
1140 tbl->name = snd_kmalloc_strdup(str, GFP_KERNEL);
1141 if (! tbl->name) {
1142 kfree(tbl);
1143 goto __unlock;
1144 }
1145 tbl->index = idx;
1146 if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
1147 kfree(tbl->name);
1148 kfree(tbl);
1149 }
1150 __unlock:
1151 up(&mixer->reg_mutex);
1152 }
1153}
1154
1155static void snd_mixer_oss_proc_init(snd_mixer_oss_t *mixer)
1156{
1157 snd_info_entry_t *entry;
1158
1159 entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
1160 mixer->card->proc_root);
1161 if (! entry)
1162 return;
1163 entry->content = SNDRV_INFO_CONTENT_TEXT;
1164 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
1165 entry->c.text.read_size = 8192;
1166 entry->c.text.read = snd_mixer_oss_proc_read;
1167 entry->c.text.write_size = 8192;
1168 entry->c.text.write = snd_mixer_oss_proc_write;
1169 entry->private_data = mixer;
1170 if (snd_info_register(entry) < 0) {
1171 snd_info_free_entry(entry);
1172 entry = NULL;
1173 }
1174 mixer->proc_entry = entry;
1175}
1176
1177static void snd_mixer_oss_proc_done(snd_mixer_oss_t *mixer)
1178{
1179 if (mixer->proc_entry) {
1180 snd_info_unregister(mixer->proc_entry);
1181 mixer->proc_entry = NULL;
1182 }
1183}
1184
1185static void snd_mixer_oss_build(snd_mixer_oss_t *mixer)
1186{
1187 static struct snd_mixer_oss_assign_table table[] = {
1188 { SOUND_MIXER_VOLUME, "Master", 0 },
1189 { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */
1190 { SOUND_MIXER_BASS, "Tone Control - Bass", 0 },
1191 { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 },
1192 { SOUND_MIXER_SYNTH, "Synth", 0 },
1193 { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */
1194 { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */
1195 { SOUND_MIXER_PCM, "PCM", 0 },
1196 { SOUND_MIXER_SPEAKER, "PC Speaker", 0 },
1197 { SOUND_MIXER_LINE, "Line", 0 },
1198 { SOUND_MIXER_MIC, "Mic", 0 },
1199 { SOUND_MIXER_CD, "CD", 0 },
1200 { SOUND_MIXER_IMIX, "Monitor Mix", 0 },
1201 { SOUND_MIXER_ALTPCM, "PCM", 1 },
1202 { SOUND_MIXER_ALTPCM, "Headphone", 0 }, /* fallback */
1203 { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */
1204 { SOUND_MIXER_RECLEV, "-- nothing --", 0 },
1205 { SOUND_MIXER_IGAIN, "Capture", 0 },
1206 { SOUND_MIXER_OGAIN, "Playback", 0 },
1207 { SOUND_MIXER_LINE1, "Aux", 0 },
1208 { SOUND_MIXER_LINE2, "Aux", 1 },
1209 { SOUND_MIXER_LINE3, "Aux", 2 },
1210 { SOUND_MIXER_DIGITAL1, "Digital", 0 },
1211 { SOUND_MIXER_DIGITAL1, "IEC958", 0 }, /* fallback */
1212 { SOUND_MIXER_DIGITAL1, "IEC958 Optical", 0 }, /* fallback */
1213 { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial", 0 }, /* fallback */
1214 { SOUND_MIXER_DIGITAL2, "Digital", 1 },
1215 { SOUND_MIXER_DIGITAL3, "Digital", 2 },
1216 { SOUND_MIXER_PHONEIN, "Phone", 0 },
1217 { SOUND_MIXER_PHONEOUT, "Master Mono", 0 },
1218 { SOUND_MIXER_PHONEOUT, "Phone", 0 }, /* fallback */
1219 { SOUND_MIXER_VIDEO, "Video", 0 },
1220 { SOUND_MIXER_RADIO, "Radio", 0 },
1221 { SOUND_MIXER_MONITOR, "Monitor", 0 }
1222 };
1223 unsigned int idx;
1224
1225 for (idx = 0; idx < ARRAY_SIZE(table); idx++)
1226 snd_mixer_oss_build_input(mixer, &table[idx], 0, 0);
1227 if (mixer->mask_recsrc) {
1228 mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
1229 mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
1230 }
1231}
1232
1233/*
1234 *
1235 */
1236
1237static int snd_mixer_oss_free1(void *private)
1238{
1239 snd_mixer_oss_t *mixer = private;
1240 snd_card_t * card;
1241 int idx;
1242
1243 snd_assert(mixer != NULL, return -ENXIO);
1244 card = mixer->card;
1245 snd_assert(mixer == card->mixer_oss, return -ENXIO);
1246 card->mixer_oss = NULL;
1247 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
1248 snd_mixer_oss_slot_t *chn = &mixer->slots[idx];
1249 if (chn->private_free)
1250 chn->private_free(chn);
1251 }
1252 kfree(mixer);
1253 return 0;
1254}
1255
1256static int snd_mixer_oss_notify_handler(snd_card_t * card, int cmd)
1257{
1258 snd_mixer_oss_t *mixer;
1259
1260 if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
1261 char name[128];
1262 int idx, err;
1263
1264 mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
1265 if (mixer == NULL)
1266 return -ENOMEM;
1267 init_MUTEX(&mixer->reg_mutex);
1268 sprintf(name, "mixer%i%i", card->number, 0);
1269 if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
1270 card, 0,
1271 &snd_mixer_oss_reg,
1272 name)) < 0) {
1273 snd_printk("unable to register OSS mixer device %i:%i\n", card->number, 0);
1274 kfree(mixer);
1275 return err;
1276 }
1277 mixer->oss_dev_alloc = 1;
1278 mixer->card = card;
1279 if (*card->mixername)
1280 strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
1281 else
1282 strlcpy(mixer->name, name, sizeof(mixer->name));
1283#ifdef SNDRV_OSS_INFO_DEV_MIXERS
1284 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
1285 card->number,
1286 mixer->name);
1287#endif
1288 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
1289 mixer->slots[idx].number = idx;
1290 card->mixer_oss = mixer;
1291 snd_mixer_oss_build(mixer);
1292 snd_mixer_oss_proc_init(mixer);
1293 } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
1294 mixer = card->mixer_oss;
1295 if (mixer == NULL || !mixer->oss_dev_alloc)
1296 return 0;
1297 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1298 mixer->oss_dev_alloc = 0;
1299 } else { /* free */
1300 mixer = card->mixer_oss;
1301 if (mixer == NULL)
1302 return 0;
1303#ifdef SNDRV_OSS_INFO_DEV_MIXERS
1304 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1305#endif
1306 if (mixer->oss_dev_alloc)
1307 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1308 snd_mixer_oss_proc_done(mixer);
1309 return snd_mixer_oss_free1(mixer);
1310 }
1311 return 0;
1312}
1313
1314static int __init alsa_mixer_oss_init(void)
1315{
1316 int idx;
1317
1318 snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1319 for (idx = 0; idx < SNDRV_CARDS; idx++) {
1320 if (snd_cards[idx])
1321 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
1322 }
1323 return 0;
1324}
1325
1326static void __exit alsa_mixer_oss_exit(void)
1327{
1328 int idx;
1329
1330 snd_mixer_oss_notify_callback = NULL;
1331 for (idx = 0; idx < SNDRV_CARDS; idx++) {
1332 if (snd_cards[idx])
1333 snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
1334 }
1335}
1336
1337module_init(alsa_mixer_oss_init)
1338module_exit(alsa_mixer_oss_exit)
1339
1340EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
diff --git a/sound/core/oss/mulaw.c b/sound/core/oss/mulaw.c
new file mode 100644
index 000000000000..44ec4c66eb19
--- /dev/null
+++ b/sound/core/oss/mulaw.c
@@ -0,0 +1,308 @@
1/*
2 * Mu-Law conversion Plug-In Interface
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 * Uros Bizjak <uros@kss-loka.si>
5 *
6 * Based on reference implementation by Sun Microsystems, Inc.
7 *
8 * This library is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Library General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sound/driver.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include "pcm_plugin.h"
29
30#define SIGN_BIT (0x80) /* Sign bit for a u-law byte. */
31#define QUANT_MASK (0xf) /* Quantization field mask. */
32#define NSEGS (8) /* Number of u-law segments. */
33#define SEG_SHIFT (4) /* Left shift for segment number. */
34#define SEG_MASK (0x70) /* Segment field mask. */
35
36static inline int val_seg(int val)
37{
38 int r = 0;
39 val >>= 7;
40 if (val & 0xf0) {
41 val >>= 4;
42 r += 4;
43 }
44 if (val & 0x0c) {
45 val >>= 2;
46 r += 2;
47 }
48 if (val & 0x02)
49 r += 1;
50 return r;
51}
52
53#define BIAS (0x84) /* Bias for linear code. */
54
55/*
56 * linear2ulaw() - Convert a linear PCM value to u-law
57 *
58 * In order to simplify the encoding process, the original linear magnitude
59 * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
60 * (33 - 8191). The result can be seen in the following encoding table:
61 *
62 * Biased Linear Input Code Compressed Code
63 * ------------------------ ---------------
64 * 00000001wxyza 000wxyz
65 * 0000001wxyzab 001wxyz
66 * 000001wxyzabc 010wxyz
67 * 00001wxyzabcd 011wxyz
68 * 0001wxyzabcde 100wxyz
69 * 001wxyzabcdef 101wxyz
70 * 01wxyzabcdefg 110wxyz
71 * 1wxyzabcdefgh 111wxyz
72 *
73 * Each biased linear code has a leading 1 which identifies the segment
74 * number. The value of the segment number is equal to 7 minus the number
75 * of leading 0's. The quantization interval is directly available as the
76 * four bits wxyz. * The trailing bits (a - h) are ignored.
77 *
78 * Ordinarily the complement of the resulting code word is used for
79 * transmission, and so the code word is complemented before it is returned.
80 *
81 * For further information see John C. Bellamy's Digital Telephony, 1982,
82 * John Wiley & Sons, pps 98-111 and 472-476.
83 */
84static unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */
85{
86 int mask;
87 int seg;
88 unsigned char uval;
89
90 /* Get the sign and the magnitude of the value. */
91 if (pcm_val < 0) {
92 pcm_val = BIAS - pcm_val;
93 mask = 0x7F;
94 } else {
95 pcm_val += BIAS;
96 mask = 0xFF;
97 }
98 if (pcm_val > 0x7FFF)
99 pcm_val = 0x7FFF;
100
101 /* Convert the scaled magnitude to segment number. */
102 seg = val_seg(pcm_val);
103
104 /*
105 * Combine the sign, segment, quantization bits;
106 * and complement the code word.
107 */
108 uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
109 return uval ^ mask;
110}
111
112/*
113 * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
114 *
115 * First, a biased linear code is derived from the code word. An unbiased
116 * output can then be obtained by subtracting 33 from the biased code.
117 *
118 * Note that this function expects to be passed the complement of the
119 * original code word. This is in keeping with ISDN conventions.
120 */
121static int ulaw2linear(unsigned char u_val)
122{
123 int t;
124
125 /* Complement to obtain normal u-law value. */
126 u_val = ~u_val;
127
128 /*
129 * Extract and bias the quantization bits. Then
130 * shift up by the segment number and subtract out the bias.
131 */
132 t = ((u_val & QUANT_MASK) << 3) + BIAS;
133 t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
134
135 return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
136}
137
138/*
139 * Basic Mu-Law plugin
140 */
141
142typedef void (*mulaw_f)(snd_pcm_plugin_t *plugin,
143 const snd_pcm_plugin_channel_t *src_channels,
144 snd_pcm_plugin_channel_t *dst_channels,
145 snd_pcm_uframes_t frames);
146
147typedef struct mulaw_private_data {
148 mulaw_f func;
149 int conv;
150} mulaw_t;
151
152static void mulaw_decode(snd_pcm_plugin_t *plugin,
153 const snd_pcm_plugin_channel_t *src_channels,
154 snd_pcm_plugin_channel_t *dst_channels,
155 snd_pcm_uframes_t frames)
156{
157#define PUT_S16_LABELS
158#include "plugin_ops.h"
159#undef PUT_S16_LABELS
160 mulaw_t *data = (mulaw_t *)plugin->extra_data;
161 void *put = put_s16_labels[data->conv];
162 int channel;
163 int nchannels = plugin->src_format.channels;
164 for (channel = 0; channel < nchannels; ++channel) {
165 char *src;
166 char *dst;
167 int src_step, dst_step;
168 snd_pcm_uframes_t frames1;
169 if (!src_channels[channel].enabled) {
170 if (dst_channels[channel].wanted)
171 snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
172 dst_channels[channel].enabled = 0;
173 continue;
174 }
175 dst_channels[channel].enabled = 1;
176 src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
177 dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
178 src_step = src_channels[channel].area.step / 8;
179 dst_step = dst_channels[channel].area.step / 8;
180 frames1 = frames;
181 while (frames1-- > 0) {
182 signed short sample = ulaw2linear(*src);
183 goto *put;
184#define PUT_S16_END after
185#include "plugin_ops.h"
186#undef PUT_S16_END
187 after:
188 src += src_step;
189 dst += dst_step;
190 }
191 }
192}
193
194static void mulaw_encode(snd_pcm_plugin_t *plugin,
195 const snd_pcm_plugin_channel_t *src_channels,
196 snd_pcm_plugin_channel_t *dst_channels,
197 snd_pcm_uframes_t frames)
198{
199#define GET_S16_LABELS
200#include "plugin_ops.h"
201#undef GET_S16_LABELS
202 mulaw_t *data = (mulaw_t *)plugin->extra_data;
203 void *get = get_s16_labels[data->conv];
204 int channel;
205 int nchannels = plugin->src_format.channels;
206 signed short sample = 0;
207 for (channel = 0; channel < nchannels; ++channel) {
208 char *src;
209 char *dst;
210 int src_step, dst_step;
211 snd_pcm_uframes_t frames1;
212 if (!src_channels[channel].enabled) {
213 if (dst_channels[channel].wanted)
214 snd_pcm_area_silence(&dst_channels[channel].area, 0, frames, plugin->dst_format.format);
215 dst_channels[channel].enabled = 0;
216 continue;
217 }
218 dst_channels[channel].enabled = 1;
219 src = src_channels[channel].area.addr + src_channels[channel].area.first / 8;
220 dst = dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
221 src_step = src_channels[channel].area.step / 8;
222 dst_step = dst_channels[channel].area.step / 8;
223 frames1 = frames;
224 while (frames1-- > 0) {
225 goto *get;
226#define GET_S16_END after
227#include "plugin_ops.h"
228#undef GET_S16_END
229 after:
230 *dst = linear2ulaw(sample);
231 src += src_step;
232 dst += dst_step;
233 }
234 }
235}
236
237static snd_pcm_sframes_t mulaw_transfer(snd_pcm_plugin_t *plugin,
238 const snd_pcm_plugin_channel_t *src_channels,
239 snd_pcm_plugin_channel_t *dst_channels,
240 snd_pcm_uframes_t frames)
241{
242 mulaw_t *data;
243
244 snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
245 if (frames == 0)
246 return 0;
247#ifdef CONFIG_SND_DEBUG
248 {
249 unsigned int channel;
250 for (channel = 0; channel < plugin->src_format.channels; channel++) {
251 snd_assert(src_channels[channel].area.first % 8 == 0 &&
252 src_channels[channel].area.step % 8 == 0,
253 return -ENXIO);
254 snd_assert(dst_channels[channel].area.first % 8 == 0 &&
255 dst_channels[channel].area.step % 8 == 0,
256 return -ENXIO);
257 }
258 }
259#endif
260 data = (mulaw_t *)plugin->extra_data;
261 data->func(plugin, src_channels, dst_channels, frames);
262 return frames;
263}
264
265int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *plug,
266 snd_pcm_plugin_format_t *src_format,
267 snd_pcm_plugin_format_t *dst_format,
268 snd_pcm_plugin_t **r_plugin)
269{
270 int err;
271 mulaw_t *data;
272 snd_pcm_plugin_t *plugin;
273 snd_pcm_plugin_format_t *format;
274 mulaw_f func;
275
276 snd_assert(r_plugin != NULL, return -ENXIO);
277 *r_plugin = NULL;
278
279 snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
280 snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
281
282 if (dst_format->format == SNDRV_PCM_FORMAT_MU_LAW) {
283 format = src_format;
284 func = mulaw_encode;
285 }
286 else if (src_format->format == SNDRV_PCM_FORMAT_MU_LAW) {
287 format = dst_format;
288 func = mulaw_decode;
289 }
290 else {
291 snd_BUG();
292 return -EINVAL;
293 }
294 snd_assert(snd_pcm_format_linear(format->format) != 0, return -ENXIO);
295
296 err = snd_pcm_plugin_build(plug, "Mu-Law<->linear conversion",
297 src_format, dst_format,
298 sizeof(mulaw_t), &plugin);
299 if (err < 0)
300 return err;
301 data = (mulaw_t*)plugin->extra_data;
302 data->func = func;
303 data->conv = getput_index(format->format);
304 snd_assert(data->conv >= 0 && data->conv < 4*2*2, return -EINVAL);
305 plugin->transfer = mulaw_transfer;
306 *r_plugin = plugin;
307 return 0;
308}
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
new file mode 100644
index 000000000000..1a805020f57a
--- /dev/null
+++ b/sound/core/oss/pcm_oss.c
@@ -0,0 +1,2530 @@
1/*
2 * Digital Audio (PCM) abstract layer / OSS compatible
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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#if 0
23#define PLUGIN_DEBUG
24#endif
25#if 0
26#define OSS_DEBUG
27#endif
28
29#include <sound/driver.h>
30#include <linux/init.h>
31#include <linux/smp_lock.h>
32#include <linux/slab.h>
33#include <linux/time.h>
34#include <linux/vmalloc.h>
35#include <linux/moduleparam.h>
36#include <sound/core.h>
37#include <sound/minors.h>
38#include <sound/pcm.h>
39#include <sound/pcm_params.h>
40#include "pcm_plugin.h"
41#include <sound/info.h>
42#include <linux/soundcard.h>
43#include <sound/initval.h>
44
45#define OSS_ALSAEMULVER _SIOR ('M', 249, int)
46
47static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
48static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
49static int nonblock_open = 1;
50
51MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
52MODULE_DESCRIPTION("PCM OSS emulation for ALSA.");
53MODULE_LICENSE("GPL");
54module_param_array(dsp_map, int, NULL, 0444);
55MODULE_PARM_DESC(dsp_map, "PCM device number assigned to 1st OSS device.");
56module_param_array(adsp_map, int, NULL, 0444);
57MODULE_PARM_DESC(adsp_map, "PCM device number assigned to 2nd OSS device.");
58module_param(nonblock_open, bool, 0644);
59MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices.");
60MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM);
61MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1);
62
63extern int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg);
64static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file);
65static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file);
66static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file);
67
68static inline mm_segment_t snd_enter_user(void)
69{
70 mm_segment_t fs = get_fs();
71 set_fs(get_ds());
72 return fs;
73}
74
75static inline void snd_leave_user(mm_segment_t fs)
76{
77 set_fs(fs);
78}
79
80static int snd_pcm_oss_plugin_clear(snd_pcm_substream_t *substream)
81{
82 snd_pcm_runtime_t *runtime = substream->runtime;
83 snd_pcm_plugin_t *plugin, *next;
84
85 plugin = runtime->oss.plugin_first;
86 while (plugin) {
87 next = plugin->next;
88 snd_pcm_plugin_free(plugin);
89 plugin = next;
90 }
91 runtime->oss.plugin_first = runtime->oss.plugin_last = NULL;
92 return 0;
93}
94
95static int snd_pcm_plugin_insert(snd_pcm_plugin_t *plugin)
96{
97 snd_pcm_runtime_t *runtime = plugin->plug->runtime;
98 plugin->next = runtime->oss.plugin_first;
99 plugin->prev = NULL;
100 if (runtime->oss.plugin_first) {
101 runtime->oss.plugin_first->prev = plugin;
102 runtime->oss.plugin_first = plugin;
103 } else {
104 runtime->oss.plugin_last =
105 runtime->oss.plugin_first = plugin;
106 }
107 return 0;
108}
109
110int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin)
111{
112 snd_pcm_runtime_t *runtime = plugin->plug->runtime;
113 plugin->next = NULL;
114 plugin->prev = runtime->oss.plugin_last;
115 if (runtime->oss.plugin_last) {
116 runtime->oss.plugin_last->next = plugin;
117 runtime->oss.plugin_last = plugin;
118 } else {
119 runtime->oss.plugin_last =
120 runtime->oss.plugin_first = plugin;
121 }
122 return 0;
123}
124
125static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames)
126{
127 snd_pcm_runtime_t *runtime = substream->runtime;
128 snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
129 frames = frames_to_bytes(runtime, frames);
130 if (buffer_size == runtime->oss.buffer_bytes)
131 return frames;
132 return (runtime->oss.buffer_bytes * frames) / buffer_size;
133}
134
135static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes)
136{
137 snd_pcm_runtime_t *runtime = substream->runtime;
138 snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream);
139 if (buffer_size == runtime->oss.buffer_bytes)
140 return bytes_to_frames(runtime, bytes);
141 return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
142}
143
144static int snd_pcm_oss_format_from(int format)
145{
146 switch (format) {
147 case AFMT_MU_LAW: return SNDRV_PCM_FORMAT_MU_LAW;
148 case AFMT_A_LAW: return SNDRV_PCM_FORMAT_A_LAW;
149 case AFMT_IMA_ADPCM: return SNDRV_PCM_FORMAT_IMA_ADPCM;
150 case AFMT_U8: return SNDRV_PCM_FORMAT_U8;
151 case AFMT_S16_LE: return SNDRV_PCM_FORMAT_S16_LE;
152 case AFMT_S16_BE: return SNDRV_PCM_FORMAT_S16_BE;
153 case AFMT_S8: return SNDRV_PCM_FORMAT_S8;
154 case AFMT_U16_LE: return SNDRV_PCM_FORMAT_U16_LE;
155 case AFMT_U16_BE: return SNDRV_PCM_FORMAT_U16_BE;
156 case AFMT_MPEG: return SNDRV_PCM_FORMAT_MPEG;
157 default: return SNDRV_PCM_FORMAT_U8;
158 }
159}
160
161static int snd_pcm_oss_format_to(int format)
162{
163 switch (format) {
164 case SNDRV_PCM_FORMAT_MU_LAW: return AFMT_MU_LAW;
165 case SNDRV_PCM_FORMAT_A_LAW: return AFMT_A_LAW;
166 case SNDRV_PCM_FORMAT_IMA_ADPCM: return AFMT_IMA_ADPCM;
167 case SNDRV_PCM_FORMAT_U8: return AFMT_U8;
168 case SNDRV_PCM_FORMAT_S16_LE: return AFMT_S16_LE;
169 case SNDRV_PCM_FORMAT_S16_BE: return AFMT_S16_BE;
170 case SNDRV_PCM_FORMAT_S8: return AFMT_S8;
171 case SNDRV_PCM_FORMAT_U16_LE: return AFMT_U16_LE;
172 case SNDRV_PCM_FORMAT_U16_BE: return AFMT_U16_BE;
173 case SNDRV_PCM_FORMAT_MPEG: return AFMT_MPEG;
174 default: return -EINVAL;
175 }
176}
177
178static int snd_pcm_oss_period_size(snd_pcm_substream_t *substream,
179 snd_pcm_hw_params_t *oss_params,
180 snd_pcm_hw_params_t *slave_params)
181{
182 size_t s;
183 size_t oss_buffer_size, oss_period_size, oss_periods;
184 size_t min_period_size, max_period_size;
185 snd_pcm_runtime_t *runtime = substream->runtime;
186 size_t oss_frame_size;
187
188 oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
189 params_channels(oss_params) / 8;
190
191 oss_buffer_size = snd_pcm_plug_client_size(substream,
192 snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
193 oss_buffer_size = 1 << ld2(oss_buffer_size);
194 if (atomic_read(&runtime->mmap_count)) {
195 if (oss_buffer_size > runtime->oss.mmap_bytes)
196 oss_buffer_size = runtime->oss.mmap_bytes;
197 }
198
199 if (substream->oss.setup &&
200 substream->oss.setup->period_size > 16)
201 oss_period_size = substream->oss.setup->period_size;
202 else if (runtime->oss.fragshift) {
203 oss_period_size = 1 << runtime->oss.fragshift;
204 if (oss_period_size > oss_buffer_size / 2)
205 oss_period_size = oss_buffer_size / 2;
206 } else {
207 int sd;
208 size_t bytes_per_sec = params_rate(oss_params) * snd_pcm_format_physical_width(params_format(oss_params)) * params_channels(oss_params) / 8;
209
210 oss_period_size = oss_buffer_size;
211 do {
212 oss_period_size /= 2;
213 } while (oss_period_size > bytes_per_sec);
214 if (runtime->oss.subdivision == 0) {
215 sd = 4;
216 if (oss_period_size / sd > 4096)
217 sd *= 2;
218 if (oss_period_size / sd < 4096)
219 sd = 1;
220 } else
221 sd = runtime->oss.subdivision;
222 oss_period_size /= sd;
223 if (oss_period_size < 16)
224 oss_period_size = 16;
225 }
226
227 min_period_size = snd_pcm_plug_client_size(substream,
228 snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
229 min_period_size *= oss_frame_size;
230 min_period_size = 1 << (ld2(min_period_size - 1) + 1);
231 if (oss_period_size < min_period_size)
232 oss_period_size = min_period_size;
233
234 max_period_size = snd_pcm_plug_client_size(substream,
235 snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
236 max_period_size *= oss_frame_size;
237 max_period_size = 1 << ld2(max_period_size);
238 if (oss_period_size > max_period_size)
239 oss_period_size = max_period_size;
240
241 oss_periods = oss_buffer_size / oss_period_size;
242
243 if (substream->oss.setup) {
244 if (substream->oss.setup->periods > 1)
245 oss_periods = substream->oss.setup->periods;
246 }
247
248 s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
249 if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
250 s = runtime->oss.maxfrags;
251 if (oss_periods > s)
252 oss_periods = s;
253
254 s = snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
255 if (s < 2)
256 s = 2;
257 if (oss_periods < s)
258 oss_periods = s;
259
260 while (oss_period_size * oss_periods > oss_buffer_size)
261 oss_period_size /= 2;
262
263 snd_assert(oss_period_size >= 16, return -EINVAL);
264 runtime->oss.period_bytes = oss_period_size;
265 runtime->oss.period_frames = 1;
266 runtime->oss.periods = oss_periods;
267 return 0;
268}
269
270static int choose_rate(snd_pcm_substream_t *substream,
271 snd_pcm_hw_params_t *params, unsigned int best_rate)
272{
273 snd_interval_t *it;
274 snd_pcm_hw_params_t *save;
275 unsigned int rate, prev;
276
277 save = kmalloc(sizeof(*save), GFP_KERNEL);
278 if (save == NULL)
279 return -ENOMEM;
280 *save = *params;
281 it = hw_param_interval(save, SNDRV_PCM_HW_PARAM_RATE);
282
283 /* try multiples of the best rate */
284 rate = best_rate;
285 for (;;) {
286 if (it->max < rate || (it->max == rate && it->openmax))
287 break;
288 if (it->min < rate || (it->min == rate && !it->openmin)) {
289 int ret;
290 ret = snd_pcm_hw_param_set(substream, params,
291 SNDRV_PCM_HW_PARAM_RATE,
292 rate, 0);
293 if (ret == (int)rate) {
294 kfree(save);
295 return rate;
296 }
297 *params = *save;
298 }
299 prev = rate;
300 rate += best_rate;
301 if (rate <= prev)
302 break;
303 }
304
305 /* not found, use the nearest rate */
306 kfree(save);
307 return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
308}
309
310static int snd_pcm_oss_change_params(snd_pcm_substream_t *substream)
311{
312 snd_pcm_runtime_t *runtime = substream->runtime;
313 snd_pcm_hw_params_t *params, *sparams;
314 snd_pcm_sw_params_t *sw_params;
315 ssize_t oss_buffer_size, oss_period_size;
316 size_t oss_frame_size;
317 int err;
318 int direct;
319 int format, sformat, n;
320 snd_mask_t sformat_mask;
321 snd_mask_t mask;
322
323 sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
324 params = kmalloc(sizeof(*params), GFP_KERNEL);
325 sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
326 if (!sw_params || !params || !sparams) {
327 snd_printd("No memory\n");
328 err = -ENOMEM;
329 goto failure;
330 }
331
332 if (atomic_read(&runtime->mmap_count)) {
333 direct = 1;
334 } else {
335 snd_pcm_oss_setup_t *setup = substream->oss.setup;
336 direct = (setup != NULL && setup->direct);
337 }
338
339 _snd_pcm_hw_params_any(sparams);
340 _snd_pcm_hw_param_setinteger(sparams, SNDRV_PCM_HW_PARAM_PERIODS);
341 _snd_pcm_hw_param_min(sparams, SNDRV_PCM_HW_PARAM_PERIODS, 2, 0);
342 snd_mask_none(&mask);
343 if (atomic_read(&runtime->mmap_count))
344 snd_mask_set(&mask, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
345 else {
346 snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_INTERLEAVED);
347 if (!direct)
348 snd_mask_set(&mask, SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
349 }
350 err = snd_pcm_hw_param_mask(substream, sparams, SNDRV_PCM_HW_PARAM_ACCESS, &mask);
351 if (err < 0) {
352 snd_printd("No usable accesses\n");
353 err = -EINVAL;
354 goto failure;
355 }
356 choose_rate(substream, sparams, runtime->oss.rate);
357 snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);
358
359 format = snd_pcm_oss_format_from(runtime->oss.format);
360
361 sformat_mask = *hw_param_mask(sparams, SNDRV_PCM_HW_PARAM_FORMAT);
362 if (direct)
363 sformat = format;
364 else
365 sformat = snd_pcm_plug_slave_format(format, &sformat_mask);
366
367 if (sformat < 0 || !snd_mask_test(&sformat_mask, sformat)) {
368 for (sformat = 0; sformat <= SNDRV_PCM_FORMAT_LAST; sformat++) {
369 if (snd_mask_test(&sformat_mask, sformat) &&
370 snd_pcm_oss_format_to(sformat) >= 0)
371 break;
372 }
373 if (sformat > SNDRV_PCM_FORMAT_LAST) {
374 snd_printd("Cannot find a format!!!\n");
375 err = -EINVAL;
376 goto failure;
377 }
378 }
379 err = _snd_pcm_hw_param_set(sparams, SNDRV_PCM_HW_PARAM_FORMAT, sformat, 0);
380 snd_assert(err >= 0, goto failure);
381
382 if (direct) {
383 memcpy(params, sparams, sizeof(*params));
384 } else {
385 _snd_pcm_hw_params_any(params);
386 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
387 SNDRV_PCM_ACCESS_RW_INTERLEAVED, 0);
388 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
389 snd_pcm_oss_format_from(runtime->oss.format), 0);
390 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
391 runtime->oss.channels, 0);
392 _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
393 runtime->oss.rate, 0);
394 pdprintf("client: access = %i, format = %i, channels = %i, rate = %i\n",
395 params_access(params), params_format(params),
396 params_channels(params), params_rate(params));
397 }
398 pdprintf("slave: access = %i, format = %i, channels = %i, rate = %i\n",
399 params_access(sparams), params_format(sparams),
400 params_channels(sparams), params_rate(sparams));
401
402 oss_frame_size = snd_pcm_format_physical_width(params_format(params)) *
403 params_channels(params) / 8;
404
405 snd_pcm_oss_plugin_clear(substream);
406 if (!direct) {
407 /* add necessary plugins */
408 snd_pcm_oss_plugin_clear(substream);
409 if ((err = snd_pcm_plug_format_plugins(substream,
410 params,
411 sparams)) < 0) {
412 snd_printd("snd_pcm_plug_format_plugins failed: %i\n", err);
413 snd_pcm_oss_plugin_clear(substream);
414 goto failure;
415 }
416 if (runtime->oss.plugin_first) {
417 snd_pcm_plugin_t *plugin;
418 if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
419 snd_printd("snd_pcm_plugin_build_io failed: %i\n", err);
420 snd_pcm_oss_plugin_clear(substream);
421 goto failure;
422 }
423 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
424 err = snd_pcm_plugin_append(plugin);
425 } else {
426 err = snd_pcm_plugin_insert(plugin);
427 }
428 if (err < 0) {
429 snd_pcm_oss_plugin_clear(substream);
430 goto failure;
431 }
432 }
433 }
434
435 err = snd_pcm_oss_period_size(substream, params, sparams);
436 if (err < 0)
437 goto failure;
438
439 n = snd_pcm_plug_slave_size(substream, runtime->oss.period_bytes / oss_frame_size);
440 err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, n, NULL);
441 snd_assert(err >= 0, goto failure);
442
443 err = snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_PERIODS,
444 runtime->oss.periods, NULL);
445 snd_assert(err >= 0, goto failure);
446
447 snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
448
449 if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, sparams)) < 0) {
450 snd_printd("HW_PARAMS failed: %i\n", err);
451 goto failure;
452 }
453
454 memset(sw_params, 0, sizeof(*sw_params));
455 if (runtime->oss.trigger) {
456 sw_params->start_threshold = 1;
457 } else {
458 sw_params->start_threshold = runtime->boundary;
459 }
460 if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
461 sw_params->stop_threshold = runtime->boundary;
462 else
463 sw_params->stop_threshold = runtime->buffer_size;
464 sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
465 sw_params->period_step = 1;
466 sw_params->sleep_min = 0;
467 sw_params->avail_min = 1;
468 sw_params->xfer_align = 1;
469 if (atomic_read(&runtime->mmap_count) ||
470 (substream->oss.setup && substream->oss.setup->nosilence)) {
471 sw_params->silence_threshold = 0;
472 sw_params->silence_size = 0;
473 } else {
474 snd_pcm_uframes_t frames;
475 frames = runtime->period_size + 16;
476 if (frames > runtime->buffer_size)
477 frames = runtime->buffer_size;
478 sw_params->silence_threshold = frames;
479 sw_params->silence_size = frames;
480 }
481
482 if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
483 snd_printd("SW_PARAMS failed: %i\n", err);
484 goto failure;
485 }
486
487 runtime->oss.periods = params_periods(sparams);
488 oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams));
489 snd_assert(oss_period_size >= 0, err = -EINVAL; goto failure);
490 if (runtime->oss.plugin_first) {
491 err = snd_pcm_plug_alloc(substream, oss_period_size);
492 if (err < 0)
493 goto failure;
494 }
495 oss_period_size *= oss_frame_size;
496
497 oss_buffer_size = oss_period_size * runtime->oss.periods;
498 snd_assert(oss_buffer_size >= 0, err = -EINVAL; goto failure);
499
500 runtime->oss.period_bytes = oss_period_size;
501 runtime->oss.buffer_bytes = oss_buffer_size;
502
503 pdprintf("oss: period bytes = %i, buffer bytes = %i\n",
504 runtime->oss.period_bytes,
505 runtime->oss.buffer_bytes);
506 pdprintf("slave: period_size = %i, buffer_size = %i\n",
507 params_period_size(sparams),
508 params_buffer_size(sparams));
509
510 runtime->oss.format = snd_pcm_oss_format_to(params_format(params));
511 runtime->oss.channels = params_channels(params);
512 runtime->oss.rate = params_rate(params);
513
514 runtime->oss.params = 0;
515 runtime->oss.prepare = 1;
516 vfree(runtime->oss.buffer);
517 runtime->oss.buffer = vmalloc(runtime->oss.period_bytes);
518 runtime->oss.buffer_used = 0;
519 if (runtime->dma_area)
520 snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes));
521
522 runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size);
523
524 err = 0;
525failure:
526 kfree(sw_params);
527 kfree(params);
528 kfree(sparams);
529 return err;
530}
531
532static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, snd_pcm_substream_t **r_substream)
533{
534 int idx, err;
535 snd_pcm_substream_t *asubstream = NULL, *substream;
536
537 for (idx = 0; idx < 2; idx++) {
538 substream = pcm_oss_file->streams[idx];
539 if (substream == NULL)
540 continue;
541 if (asubstream == NULL)
542 asubstream = substream;
543 if (substream->runtime->oss.params) {
544 err = snd_pcm_oss_change_params(substream);
545 if (err < 0)
546 return err;
547 }
548 }
549 snd_assert(asubstream != NULL, return -EIO);
550 if (r_substream)
551 *r_substream = asubstream;
552 return 0;
553}
554
555static int snd_pcm_oss_prepare(snd_pcm_substream_t *substream)
556{
557 int err;
558 snd_pcm_runtime_t *runtime = substream->runtime;
559
560 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
561 if (err < 0) {
562 snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n");
563 return err;
564 }
565 runtime->oss.prepare = 0;
566 runtime->oss.prev_hw_ptr_interrupt = 0;
567 runtime->oss.period_ptr = 0;
568 runtime->oss.buffer_used = 0;
569
570 return 0;
571}
572
573static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream)
574{
575 snd_pcm_runtime_t *runtime;
576 int err;
577
578 if (substream == NULL)
579 return 0;
580 runtime = substream->runtime;
581 if (runtime->oss.params) {
582 err = snd_pcm_oss_change_params(substream);
583 if (err < 0)
584 return err;
585 }
586 if (runtime->oss.prepare) {
587 err = snd_pcm_oss_prepare(substream);
588 if (err < 0)
589 return err;
590 }
591 return 0;
592}
593
594static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, snd_pcm_sframes_t *delay)
595{
596 snd_pcm_runtime_t *runtime;
597 snd_pcm_uframes_t frames;
598 int err = 0;
599
600 while (1) {
601 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);
602 if (err < 0)
603 break;
604 runtime = substream->runtime;
605 if (*delay <= (snd_pcm_sframes_t)runtime->buffer_size)
606 break;
607 /* in case of overrun, skip whole periods like OSS/Linux driver does */
608 /* until avail(delay) <= buffer_size */
609 frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
610 frames /= runtime->period_size;
611 frames *= runtime->period_size;
612 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);
613 if (err < 0)
614 break;
615 }
616 return err;
617}
618
619snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
620{
621 snd_pcm_runtime_t *runtime = substream->runtime;
622 int ret;
623 while (1) {
624 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
625 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
626#ifdef OSS_DEBUG
627 if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
628 printk("pcm_oss: write: recovering from XRUN\n");
629 else
630 printk("pcm_oss: write: recovering from SUSPEND\n");
631#endif
632 ret = snd_pcm_oss_prepare(substream);
633 if (ret < 0)
634 break;
635 }
636 if (in_kernel) {
637 mm_segment_t fs;
638 fs = snd_enter_user();
639 ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
640 snd_leave_user(fs);
641 } else {
642 ret = snd_pcm_lib_write(substream, (void __user *)ptr, frames);
643 }
644 if (ret != -EPIPE && ret != -ESTRPIPE)
645 break;
646 /* test, if we can't store new data, because the stream */
647 /* has not been started */
648 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
649 return -EAGAIN;
650 }
651 return ret;
652}
653
654snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
655{
656 snd_pcm_runtime_t *runtime = substream->runtime;
657 snd_pcm_sframes_t delay;
658 int ret;
659 while (1) {
660 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
661 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
662#ifdef OSS_DEBUG
663 if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
664 printk("pcm_oss: read: recovering from XRUN\n");
665 else
666 printk("pcm_oss: read: recovering from SUSPEND\n");
667#endif
668 ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
669 if (ret < 0)
670 break;
671 } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
672 ret = snd_pcm_oss_prepare(substream);
673 if (ret < 0)
674 break;
675 }
676 ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
677 if (ret < 0)
678 break;
679 if (in_kernel) {
680 mm_segment_t fs;
681 fs = snd_enter_user();
682 ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
683 snd_leave_user(fs);
684 } else {
685 ret = snd_pcm_lib_read(substream, (void __user *)ptr, frames);
686 }
687 if (ret == -EPIPE) {
688 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
689 ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
690 if (ret < 0)
691 break;
692 }
693 continue;
694 }
695 if (ret != -ESTRPIPE)
696 break;
697 }
698 return ret;
699}
700
701snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
702{
703 snd_pcm_runtime_t *runtime = substream->runtime;
704 int ret;
705 while (1) {
706 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
707 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
708#ifdef OSS_DEBUG
709 if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
710 printk("pcm_oss: writev: recovering from XRUN\n");
711 else
712 printk("pcm_oss: writev: recovering from SUSPEND\n");
713#endif
714 ret = snd_pcm_oss_prepare(substream);
715 if (ret < 0)
716 break;
717 }
718 if (in_kernel) {
719 mm_segment_t fs;
720 fs = snd_enter_user();
721 ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
722 snd_leave_user(fs);
723 } else {
724 ret = snd_pcm_lib_writev(substream, (void __user **)bufs, frames);
725 }
726 if (ret != -EPIPE && ret != -ESTRPIPE)
727 break;
728
729 /* test, if we can't store new data, because the stream */
730 /* has not been started */
731 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED)
732 return -EAGAIN;
733 }
734 return ret;
735}
736
737snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel)
738{
739 snd_pcm_runtime_t *runtime = substream->runtime;
740 int ret;
741 while (1) {
742 if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
743 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
744#ifdef OSS_DEBUG
745 if (runtime->status->state == SNDRV_PCM_STATE_XRUN)
746 printk("pcm_oss: readv: recovering from XRUN\n");
747 else
748 printk("pcm_oss: readv: recovering from SUSPEND\n");
749#endif
750 ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
751 if (ret < 0)
752 break;
753 } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) {
754 ret = snd_pcm_oss_prepare(substream);
755 if (ret < 0)
756 break;
757 }
758 if (in_kernel) {
759 mm_segment_t fs;
760 fs = snd_enter_user();
761 ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
762 snd_leave_user(fs);
763 } else {
764 ret = snd_pcm_lib_readv(substream, (void __user **)bufs, frames);
765 }
766 if (ret != -EPIPE && ret != -ESTRPIPE)
767 break;
768 }
769 return ret;
770}
771
772static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *buf, size_t bytes, int in_kernel)
773{
774 snd_pcm_runtime_t *runtime = substream->runtime;
775 snd_pcm_sframes_t frames, frames1;
776 if (runtime->oss.plugin_first) {
777 snd_pcm_plugin_channel_t *channels;
778 size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8;
779 if (!in_kernel) {
780 if (copy_from_user(runtime->oss.buffer, (const char __user *)buf, bytes))
781 return -EFAULT;
782 buf = runtime->oss.buffer;
783 }
784 frames = bytes / oss_frame_bytes;
785 frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels);
786 if (frames1 < 0)
787 return frames1;
788 frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1);
789 if (frames1 <= 0)
790 return frames1;
791 bytes = frames1 * oss_frame_bytes;
792 } else {
793 frames = bytes_to_frames(runtime, bytes);
794 frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel);
795 if (frames1 <= 0)
796 return frames1;
797 bytes = frames_to_bytes(runtime, frames1);
798 }
799 return bytes;
800}
801
802static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char __user *buf, size_t bytes)
803{
804 size_t xfer = 0;
805 ssize_t tmp;
806 snd_pcm_runtime_t *runtime = substream->runtime;
807
808 if (atomic_read(&runtime->mmap_count))
809 return -ENXIO;
810
811 if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
812 return tmp;
813 while (bytes > 0) {
814 if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
815 tmp = bytes;
816 if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
817 tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
818 if (tmp > 0) {
819 if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp))
820 return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;
821 }
822 runtime->oss.buffer_used += tmp;
823 buf += tmp;
824 bytes -= tmp;
825 xfer += tmp;
826 if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) ||
827 runtime->oss.buffer_used == runtime->oss.period_bytes) {
828 tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
829 runtime->oss.buffer_used - runtime->oss.period_ptr, 1);
830 if (tmp <= 0)
831 return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
832 runtime->oss.bytes += tmp;
833 runtime->oss.period_ptr += tmp;
834 runtime->oss.period_ptr %= runtime->oss.period_bytes;
835 if (runtime->oss.period_ptr == 0 ||
836 runtime->oss.period_ptr == runtime->oss.buffer_used)
837 runtime->oss.buffer_used = 0;
838 else if ((substream->ffile->f_flags & O_NONBLOCK) != 0)
839 return xfer > 0 ? xfer : -EAGAIN;
840 }
841 } else {
842 tmp = snd_pcm_oss_write2(substream, (const char *)buf, runtime->oss.period_bytes, 0);
843 if (tmp <= 0)
844 return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
845 runtime->oss.bytes += tmp;
846 buf += tmp;
847 bytes -= tmp;
848 xfer += tmp;
849 if ((substream->ffile->f_flags & O_NONBLOCK) != 0 &&
850 tmp != runtime->oss.period_bytes)
851 break;
852 }
853 }
854 return xfer;
855}
856
857static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size_t bytes, int in_kernel)
858{
859 snd_pcm_runtime_t *runtime = substream->runtime;
860 snd_pcm_sframes_t frames, frames1;
861 char __user *final_dst = (char __user *)buf;
862 if (runtime->oss.plugin_first) {
863 snd_pcm_plugin_channel_t *channels;
864 size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8;
865 if (!in_kernel)
866 buf = runtime->oss.buffer;
867 frames = bytes / oss_frame_bytes;
868 frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels);
869 if (frames1 < 0)
870 return frames1;
871 frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1);
872 if (frames1 <= 0)
873 return frames1;
874 bytes = frames1 * oss_frame_bytes;
875 if (!in_kernel && copy_to_user(final_dst, buf, bytes))
876 return -EFAULT;
877 } else {
878 frames = bytes_to_frames(runtime, bytes);
879 frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel);
880 if (frames1 <= 0)
881 return frames1;
882 bytes = frames_to_bytes(runtime, frames1);
883 }
884 return bytes;
885}
886
887static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char __user *buf, size_t bytes)
888{
889 size_t xfer = 0;
890 ssize_t tmp;
891 snd_pcm_runtime_t *runtime = substream->runtime;
892
893 if (atomic_read(&runtime->mmap_count))
894 return -ENXIO;
895
896 if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
897 return tmp;
898 while (bytes > 0) {
899 if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
900 if (runtime->oss.buffer_used == 0) {
901 tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
902 if (tmp <= 0)
903 return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
904 runtime->oss.bytes += tmp;
905 runtime->oss.period_ptr = tmp;
906 runtime->oss.buffer_used = tmp;
907 }
908 tmp = bytes;
909 if ((size_t) tmp > runtime->oss.buffer_used)
910 tmp = runtime->oss.buffer_used;
911 if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp))
912 return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT;
913 buf += tmp;
914 bytes -= tmp;
915 xfer += tmp;
916 runtime->oss.buffer_used -= tmp;
917 } else {
918 tmp = snd_pcm_oss_read2(substream, (char *)buf, runtime->oss.period_bytes, 0);
919 if (tmp <= 0)
920 return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
921 runtime->oss.bytes += tmp;
922 buf += tmp;
923 bytes -= tmp;
924 xfer += tmp;
925 }
926 }
927 return xfer;
928}
929
930static int snd_pcm_oss_reset(snd_pcm_oss_file_t *pcm_oss_file)
931{
932 snd_pcm_substream_t *substream;
933
934 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
935 if (substream != NULL) {
936 snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
937 substream->runtime->oss.prepare = 1;
938 }
939 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
940 if (substream != NULL) {
941 snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
942 substream->runtime->oss.prepare = 1;
943 }
944 return 0;
945}
946
947static int snd_pcm_oss_post(snd_pcm_oss_file_t *pcm_oss_file)
948{
949 snd_pcm_substream_t *substream;
950 int err;
951
952 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
953 if (substream != NULL) {
954 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
955 return err;
956 snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
957 }
958 /* note: all errors from the start action are ignored */
959 /* OSS apps do not know, how to handle them */
960 return 0;
961}
962
963static int snd_pcm_oss_sync1(snd_pcm_substream_t *substream, size_t size)
964{
965 snd_pcm_runtime_t *runtime;
966 ssize_t result = 0;
967 long res;
968 wait_queue_t wait;
969
970 runtime = substream->runtime;
971 init_waitqueue_entry(&wait, current);
972 add_wait_queue(&runtime->sleep, &wait);
973#ifdef OSS_DEBUG
974 printk("sync1: size = %li\n", size);
975#endif
976 while (1) {
977 result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1);
978 if (result > 0) {
979 runtime->oss.buffer_used = 0;
980 result = 0;
981 break;
982 }
983 if (result != 0 && result != -EAGAIN)
984 break;
985 result = 0;
986 set_current_state(TASK_INTERRUPTIBLE);
987 snd_pcm_stream_lock_irq(substream);
988 res = runtime->status->state;
989 snd_pcm_stream_unlock_irq(substream);
990 if (res != SNDRV_PCM_STATE_RUNNING) {
991 set_current_state(TASK_RUNNING);
992 break;
993 }
994 res = schedule_timeout(10 * HZ);
995 if (signal_pending(current)) {
996 result = -ERESTARTSYS;
997 break;
998 }
999 if (res == 0) {
1000 snd_printk(KERN_ERR "OSS sync error - DMA timeout\n");
1001 result = -EIO;
1002 break;
1003 }
1004 }
1005 remove_wait_queue(&runtime->sleep, &wait);
1006 return result;
1007}
1008
1009static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file)
1010{
1011 int err = 0;
1012 unsigned int saved_f_flags;
1013 snd_pcm_substream_t *substream;
1014 snd_pcm_runtime_t *runtime;
1015 snd_pcm_format_t format;
1016 unsigned long width;
1017 size_t size;
1018
1019 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1020 if (substream != NULL) {
1021 runtime = substream->runtime;
1022 if (atomic_read(&runtime->mmap_count))
1023 goto __direct;
1024 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1025 return err;
1026 format = snd_pcm_oss_format_from(runtime->oss.format);
1027 width = snd_pcm_format_physical_width(format);
1028 if (runtime->oss.buffer_used > 0) {
1029#ifdef OSS_DEBUG
1030 printk("sync: buffer_used\n");
1031#endif
1032 size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width;
1033 snd_pcm_format_set_silence(format,
1034 runtime->oss.buffer + runtime->oss.buffer_used,
1035 size);
1036 err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
1037 if (err < 0)
1038 return err;
1039 } else if (runtime->oss.period_ptr > 0) {
1040#ifdef OSS_DEBUG
1041 printk("sync: period_ptr\n");
1042#endif
1043 size = runtime->oss.period_bytes - runtime->oss.period_ptr;
1044 snd_pcm_format_set_silence(format,
1045 runtime->oss.buffer,
1046 size * 8 / width);
1047 err = snd_pcm_oss_sync1(substream, size);
1048 if (err < 0)
1049 return err;
1050 }
1051 /*
1052 * The ALSA's period might be a bit large than OSS one.
1053 * Fill the remain portion of ALSA period with zeros.
1054 */
1055 size = runtime->control->appl_ptr % runtime->period_size;
1056 if (size > 0) {
1057 size = runtime->period_size - size;
1058 if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
1059 size = (runtime->frame_bits * size) / 8;
1060 while (size > 0) {
1061 mm_segment_t fs;
1062 size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes;
1063 size -= size1;
1064 size1 *= 8;
1065 size1 /= runtime->sample_bits;
1066 snd_pcm_format_set_silence(runtime->format,
1067 runtime->oss.buffer,
1068 size1);
1069 fs = snd_enter_user();
1070 snd_pcm_lib_write(substream, (void __user *)runtime->oss.buffer, size1);
1071 snd_leave_user(fs);
1072 }
1073 } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
1074 void __user *buffers[runtime->channels];
1075 memset(buffers, 0, runtime->channels * sizeof(void *));
1076 snd_pcm_lib_writev(substream, buffers, size);
1077 }
1078 }
1079 /*
1080 * finish sync: drain the buffer
1081 */
1082 __direct:
1083 saved_f_flags = substream->ffile->f_flags;
1084 substream->ffile->f_flags &= ~O_NONBLOCK;
1085 err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, NULL);
1086 substream->ffile->f_flags = saved_f_flags;
1087 if (err < 0)
1088 return err;
1089 runtime->oss.prepare = 1;
1090 }
1091
1092 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1093 if (substream != NULL) {
1094 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1095 return err;
1096 runtime = substream->runtime;
1097 err = snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
1098 if (err < 0)
1099 return err;
1100 runtime->oss.buffer_used = 0;
1101 runtime->oss.prepare = 1;
1102 }
1103 return 0;
1104}
1105
1106static int snd_pcm_oss_set_rate(snd_pcm_oss_file_t *pcm_oss_file, int rate)
1107{
1108 int idx;
1109
1110 for (idx = 1; idx >= 0; --idx) {
1111 snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
1112 snd_pcm_runtime_t *runtime;
1113 if (substream == NULL)
1114 continue;
1115 runtime = substream->runtime;
1116 if (rate < 1000)
1117 rate = 1000;
1118 else if (rate > 192000)
1119 rate = 192000;
1120 if (runtime->oss.rate != rate) {
1121 runtime->oss.params = 1;
1122 runtime->oss.rate = rate;
1123 }
1124 }
1125 return snd_pcm_oss_get_rate(pcm_oss_file);
1126}
1127
1128static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file)
1129{
1130 snd_pcm_substream_t *substream;
1131 int err;
1132
1133 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1134 return err;
1135 return substream->runtime->oss.rate;
1136}
1137
1138static int snd_pcm_oss_set_channels(snd_pcm_oss_file_t *pcm_oss_file, unsigned int channels)
1139{
1140 int idx;
1141 if (channels < 1)
1142 channels = 1;
1143 if (channels > 128)
1144 return -EINVAL;
1145 for (idx = 1; idx >= 0; --idx) {
1146 snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
1147 snd_pcm_runtime_t *runtime;
1148 if (substream == NULL)
1149 continue;
1150 runtime = substream->runtime;
1151 if (runtime->oss.channels != channels) {
1152 runtime->oss.params = 1;
1153 runtime->oss.channels = channels;
1154 }
1155 }
1156 return snd_pcm_oss_get_channels(pcm_oss_file);
1157}
1158
1159static int snd_pcm_oss_get_channels(snd_pcm_oss_file_t *pcm_oss_file)
1160{
1161 snd_pcm_substream_t *substream;
1162 int err;
1163
1164 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1165 return err;
1166 return substream->runtime->oss.channels;
1167}
1168
1169static int snd_pcm_oss_get_block_size(snd_pcm_oss_file_t *pcm_oss_file)
1170{
1171 snd_pcm_substream_t *substream;
1172 int err;
1173
1174 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1175 return err;
1176 return substream->runtime->oss.period_bytes;
1177}
1178
1179static int snd_pcm_oss_get_formats(snd_pcm_oss_file_t *pcm_oss_file)
1180{
1181 snd_pcm_substream_t *substream;
1182 int err;
1183 int direct;
1184 snd_pcm_hw_params_t *params;
1185 unsigned int formats = 0;
1186 snd_mask_t format_mask;
1187 int fmt;
1188
1189 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1190 return err;
1191 if (atomic_read(&substream->runtime->mmap_count)) {
1192 direct = 1;
1193 } else {
1194 snd_pcm_oss_setup_t *setup = substream->oss.setup;
1195 direct = (setup != NULL && setup->direct);
1196 }
1197 if (!direct)
1198 return AFMT_MU_LAW | AFMT_U8 |
1199 AFMT_S16_LE | AFMT_S16_BE |
1200 AFMT_S8 | AFMT_U16_LE |
1201 AFMT_U16_BE;
1202 params = kmalloc(sizeof(*params), GFP_KERNEL);
1203 if (!params)
1204 return -ENOMEM;
1205 _snd_pcm_hw_params_any(params);
1206 err = snd_pcm_hw_refine(substream, params);
1207 format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1208 kfree(params);
1209 snd_assert(err >= 0, return err);
1210 for (fmt = 0; fmt < 32; ++fmt) {
1211 if (snd_mask_test(&format_mask, fmt)) {
1212 int f = snd_pcm_oss_format_to(fmt);
1213 if (f >= 0)
1214 formats |= f;
1215 }
1216 }
1217 return formats;
1218}
1219
1220static int snd_pcm_oss_set_format(snd_pcm_oss_file_t *pcm_oss_file, int format)
1221{
1222 int formats, idx;
1223
1224 if (format != AFMT_QUERY) {
1225 formats = snd_pcm_oss_get_formats(pcm_oss_file);
1226 if (!(formats & format))
1227 format = AFMT_U8;
1228 for (idx = 1; idx >= 0; --idx) {
1229 snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
1230 snd_pcm_runtime_t *runtime;
1231 if (substream == NULL)
1232 continue;
1233 runtime = substream->runtime;
1234 if (runtime->oss.format != format) {
1235 runtime->oss.params = 1;
1236 runtime->oss.format = format;
1237 }
1238 }
1239 }
1240 return snd_pcm_oss_get_format(pcm_oss_file);
1241}
1242
1243static int snd_pcm_oss_get_format(snd_pcm_oss_file_t *pcm_oss_file)
1244{
1245 snd_pcm_substream_t *substream;
1246 int err;
1247
1248 if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
1249 return err;
1250 return substream->runtime->oss.format;
1251}
1252
1253static int snd_pcm_oss_set_subdivide1(snd_pcm_substream_t *substream, int subdivide)
1254{
1255 snd_pcm_runtime_t *runtime;
1256
1257 if (substream == NULL)
1258 return 0;
1259 runtime = substream->runtime;
1260 if (subdivide == 0) {
1261 subdivide = runtime->oss.subdivision;
1262 if (subdivide == 0)
1263 subdivide = 1;
1264 return subdivide;
1265 }
1266 if (runtime->oss.subdivision || runtime->oss.fragshift)
1267 return -EINVAL;
1268 if (subdivide != 1 && subdivide != 2 && subdivide != 4 &&
1269 subdivide != 8 && subdivide != 16)
1270 return -EINVAL;
1271 runtime->oss.subdivision = subdivide;
1272 runtime->oss.params = 1;
1273 return subdivide;
1274}
1275
1276static int snd_pcm_oss_set_subdivide(snd_pcm_oss_file_t *pcm_oss_file, int subdivide)
1277{
1278 int err = -EINVAL, idx;
1279
1280 for (idx = 1; idx >= 0; --idx) {
1281 snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
1282 if (substream == NULL)
1283 continue;
1284 if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
1285 return err;
1286 }
1287 return err;
1288}
1289
1290static int snd_pcm_oss_set_fragment1(snd_pcm_substream_t *substream, unsigned int val)
1291{
1292 snd_pcm_runtime_t *runtime;
1293
1294 if (substream == NULL)
1295 return 0;
1296 runtime = substream->runtime;
1297 if (runtime->oss.subdivision || runtime->oss.fragshift)
1298 return -EINVAL;
1299 runtime->oss.fragshift = val & 0xffff;
1300 runtime->oss.maxfrags = (val >> 16) & 0xffff;
1301 if (runtime->oss.fragshift < 4) /* < 16 */
1302 runtime->oss.fragshift = 4;
1303 if (runtime->oss.maxfrags < 2)
1304 runtime->oss.maxfrags = 2;
1305 runtime->oss.params = 1;
1306 return 0;
1307}
1308
1309static int snd_pcm_oss_set_fragment(snd_pcm_oss_file_t *pcm_oss_file, unsigned int val)
1310{
1311 int err = -EINVAL, idx;
1312
1313 for (idx = 1; idx >= 0; --idx) {
1314 snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
1315 if (substream == NULL)
1316 continue;
1317 if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
1318 return err;
1319 }
1320 return err;
1321}
1322
1323static int snd_pcm_oss_nonblock(struct file * file)
1324{
1325 file->f_flags |= O_NONBLOCK;
1326 return 0;
1327}
1328
1329static int snd_pcm_oss_get_caps1(snd_pcm_substream_t *substream, int res)
1330{
1331
1332 if (substream == NULL) {
1333 res &= ~DSP_CAP_DUPLEX;
1334 return res;
1335 }
1336#ifdef DSP_CAP_MULTI
1337 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1338 if (substream->pstr->substream_count > 1)
1339 res |= DSP_CAP_MULTI;
1340#endif
1341 /* DSP_CAP_REALTIME is set all times: */
1342 /* all ALSA drivers can return actual pointer in ring buffer */
1343#if defined(DSP_CAP_REALTIME) && 0
1344 {
1345 snd_pcm_runtime_t *runtime = substream->runtime;
1346 if (runtime->info & (SNDRV_PCM_INFO_BLOCK_TRANSFER|SNDRV_PCM_INFO_BATCH))
1347 res &= ~DSP_CAP_REALTIME;
1348 }
1349#endif
1350 return res;
1351}
1352
1353static int snd_pcm_oss_get_caps(snd_pcm_oss_file_t *pcm_oss_file)
1354{
1355 int result, idx;
1356
1357 result = DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_DUPLEX | DSP_CAP_REALTIME;
1358 for (idx = 0; idx < 2; idx++) {
1359 snd_pcm_substream_t *substream = pcm_oss_file->streams[idx];
1360 result = snd_pcm_oss_get_caps1(substream, result);
1361 }
1362 result |= 0x0001; /* revision - same as SB AWE 64 */
1363 return result;
1364}
1365
1366static void snd_pcm_oss_simulate_fill(snd_pcm_substream_t *substream, snd_pcm_uframes_t hw_ptr)
1367{
1368 snd_pcm_runtime_t *runtime = substream->runtime;
1369 snd_pcm_uframes_t appl_ptr;
1370 appl_ptr = hw_ptr + runtime->buffer_size;
1371 appl_ptr %= runtime->boundary;
1372 runtime->control->appl_ptr = appl_ptr;
1373}
1374
1375static int snd_pcm_oss_set_trigger(snd_pcm_oss_file_t *pcm_oss_file, int trigger)
1376{
1377 snd_pcm_runtime_t *runtime;
1378 snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
1379 int err, cmd;
1380
1381#ifdef OSS_DEBUG
1382 printk("pcm_oss: trigger = 0x%x\n", trigger);
1383#endif
1384
1385 psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1386 csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1387
1388 if (psubstream) {
1389 if ((err = snd_pcm_oss_make_ready(psubstream)) < 0)
1390 return err;
1391 }
1392 if (csubstream) {
1393 if ((err = snd_pcm_oss_make_ready(csubstream)) < 0)
1394 return err;
1395 }
1396 if (psubstream) {
1397 runtime = psubstream->runtime;
1398 if (trigger & PCM_ENABLE_OUTPUT) {
1399 if (runtime->oss.trigger)
1400 goto _skip1;
1401 if (atomic_read(&psubstream->runtime->mmap_count))
1402 snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt);
1403 runtime->oss.trigger = 1;
1404 runtime->start_threshold = 1;
1405 cmd = SNDRV_PCM_IOCTL_START;
1406 } else {
1407 if (!runtime->oss.trigger)
1408 goto _skip1;
1409 runtime->oss.trigger = 0;
1410 runtime->start_threshold = runtime->boundary;
1411 cmd = SNDRV_PCM_IOCTL_DROP;
1412 runtime->oss.prepare = 1;
1413 }
1414 err = snd_pcm_kernel_playback_ioctl(psubstream, cmd, NULL);
1415 if (err < 0)
1416 return err;
1417 }
1418 _skip1:
1419 if (csubstream) {
1420 runtime = csubstream->runtime;
1421 if (trigger & PCM_ENABLE_INPUT) {
1422 if (runtime->oss.trigger)
1423 goto _skip2;
1424 runtime->oss.trigger = 1;
1425 runtime->start_threshold = 1;
1426 cmd = SNDRV_PCM_IOCTL_START;
1427 } else {
1428 if (!runtime->oss.trigger)
1429 goto _skip2;
1430 runtime->oss.trigger = 0;
1431 runtime->start_threshold = runtime->boundary;
1432 cmd = SNDRV_PCM_IOCTL_DROP;
1433 runtime->oss.prepare = 1;
1434 }
1435 err = snd_pcm_kernel_capture_ioctl(csubstream, cmd, NULL);
1436 if (err < 0)
1437 return err;
1438 }
1439 _skip2:
1440 return 0;
1441}
1442
1443static int snd_pcm_oss_get_trigger(snd_pcm_oss_file_t *pcm_oss_file)
1444{
1445 snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
1446 int result = 0;
1447
1448 psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1449 csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1450 if (psubstream && psubstream->runtime && psubstream->runtime->oss.trigger)
1451 result |= PCM_ENABLE_OUTPUT;
1452 if (csubstream && csubstream->runtime && csubstream->runtime->oss.trigger)
1453 result |= PCM_ENABLE_INPUT;
1454 return result;
1455}
1456
1457static int snd_pcm_oss_get_odelay(snd_pcm_oss_file_t *pcm_oss_file)
1458{
1459 snd_pcm_substream_t *substream;
1460 snd_pcm_runtime_t *runtime;
1461 snd_pcm_sframes_t delay;
1462 int err;
1463
1464 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1465 if (substream == NULL)
1466 return -EINVAL;
1467 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1468 return err;
1469 runtime = substream->runtime;
1470 if (runtime->oss.params || runtime->oss.prepare)
1471 return 0;
1472 err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
1473 if (err == -EPIPE)
1474 delay = 0; /* hack for broken OSS applications */
1475 else if (err < 0)
1476 return err;
1477 return snd_pcm_oss_bytes(substream, delay);
1478}
1479
1480static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct count_info __user * _info)
1481{
1482 snd_pcm_substream_t *substream;
1483 snd_pcm_runtime_t *runtime;
1484 snd_pcm_sframes_t delay;
1485 int fixup;
1486 struct count_info info;
1487 int err;
1488
1489 if (_info == NULL)
1490 return -EFAULT;
1491 substream = pcm_oss_file->streams[stream];
1492 if (substream == NULL)
1493 return -EINVAL;
1494 if ((err = snd_pcm_oss_make_ready(substream)) < 0)
1495 return err;
1496 runtime = substream->runtime;
1497 if (runtime->oss.params || runtime->oss.prepare) {
1498 memset(&info, 0, sizeof(info));
1499 if (copy_to_user(_info, &info, sizeof(info)))
1500 return -EFAULT;
1501 return 0;
1502 }
1503 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1504 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
1505 if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) {
1506 err = 0;
1507 delay = 0;
1508 fixup = 0;
1509 } else {
1510 fixup = runtime->oss.buffer_used;
1511 }
1512 } else {
1513 err = snd_pcm_oss_capture_position_fixup(substream, &delay);
1514 fixup = -runtime->oss.buffer_used;
1515 }
1516 if (err < 0)
1517 return err;
1518 info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
1519 if (atomic_read(&runtime->mmap_count)) {
1520 snd_pcm_sframes_t n;
1521 n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt;
1522 if (n < 0)
1523 n += runtime->boundary;
1524 info.blocks = n / runtime->period_size;
1525 runtime->oss.prev_hw_ptr_interrupt = delay;
1526 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1527 snd_pcm_oss_simulate_fill(substream, delay);
1528 info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
1529 } else {
1530 delay = snd_pcm_oss_bytes(substream, delay) + fixup;
1531 info.blocks = delay / runtime->oss.period_bytes;
1532 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
1533 info.bytes = (runtime->oss.bytes - delay) & INT_MAX;
1534 else
1535 info.bytes = (runtime->oss.bytes + delay) & INT_MAX;
1536 }
1537 if (copy_to_user(_info, &info, sizeof(info)))
1538 return -EFAULT;
1539 return 0;
1540}
1541
1542static int snd_pcm_oss_get_space(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct audio_buf_info __user *_info)
1543{
1544 snd_pcm_substream_t *substream;
1545 snd_pcm_runtime_t *runtime;
1546 snd_pcm_sframes_t avail;
1547 int fixup;
1548 struct audio_buf_info info;
1549 int err;
1550
1551 if (_info == NULL)
1552 return -EFAULT;
1553 substream = pcm_oss_file->streams[stream];
1554 if (substream == NULL)
1555 return -EINVAL;
1556 runtime = substream->runtime;
1557
1558 if (runtime->oss.params &&
1559 (err = snd_pcm_oss_change_params(substream)) < 0)
1560 return err;
1561
1562 info.fragsize = runtime->oss.period_bytes;
1563 info.fragstotal = runtime->periods;
1564 if (runtime->oss.prepare) {
1565 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1566 info.bytes = runtime->oss.period_bytes * runtime->oss.periods;
1567 info.fragments = runtime->oss.periods;
1568 } else {
1569 info.bytes = 0;
1570 info.fragments = 0;
1571 }
1572 } else {
1573 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
1574 err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail);
1575 if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) {
1576 avail = runtime->buffer_size;
1577 err = 0;
1578 fixup = 0;
1579 } else {
1580 avail = runtime->buffer_size - avail;
1581 fixup = -runtime->oss.buffer_used;
1582 }
1583 } else {
1584 err = snd_pcm_oss_capture_position_fixup(substream, &avail);
1585 fixup = runtime->oss.buffer_used;
1586 }
1587 if (err < 0)
1588 return err;
1589 info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup;
1590 info.fragments = info.bytes / runtime->oss.period_bytes;
1591 }
1592
1593#ifdef OSS_DEBUG
1594 printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
1595#endif
1596 if (copy_to_user(_info, &info, sizeof(info)))
1597 return -EFAULT;
1598 return 0;
1599}
1600
1601static int snd_pcm_oss_get_mapbuf(snd_pcm_oss_file_t *pcm_oss_file, int stream, struct buffmem_desc __user * _info)
1602{
1603 // it won't be probably implemented
1604 // snd_printd("TODO: snd_pcm_oss_get_mapbuf\n");
1605 return -EINVAL;
1606}
1607
1608static snd_pcm_oss_setup_t *snd_pcm_oss_look_for_setup(snd_pcm_t *pcm, int stream, const char *task_name)
1609{
1610 const char *ptr, *ptrl;
1611 snd_pcm_oss_setup_t *setup;
1612
1613 down(&pcm->streams[stream].oss.setup_mutex);
1614 for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
1615 if (!strcmp(setup->task_name, task_name)) {
1616 up(&pcm->streams[stream].oss.setup_mutex);
1617 return setup;
1618 }
1619 }
1620 ptr = ptrl = task_name;
1621 while (*ptr) {
1622 if (*ptr == '/')
1623 ptrl = ptr + 1;
1624 ptr++;
1625 }
1626 if (ptrl == task_name) {
1627 goto __not_found;
1628 return NULL;
1629 }
1630 for (setup = pcm->streams[stream].oss.setup_list; setup; setup = setup->next) {
1631 if (!strcmp(setup->task_name, ptrl)) {
1632 up(&pcm->streams[stream].oss.setup_mutex);
1633 return setup;
1634 }
1635 }
1636 __not_found:
1637 up(&pcm->streams[stream].oss.setup_mutex);
1638 return NULL;
1639}
1640
1641static void snd_pcm_oss_init_substream(snd_pcm_substream_t *substream,
1642 snd_pcm_oss_setup_t *setup,
1643 int minor)
1644{
1645 snd_pcm_runtime_t *runtime;
1646
1647 substream->oss.oss = 1;
1648 substream->oss.setup = setup;
1649 runtime = substream->runtime;
1650 runtime->oss.params = 1;
1651 runtime->oss.trigger = 1;
1652 runtime->oss.rate = 8000;
1653 switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
1654 case SNDRV_MINOR_OSS_PCM_8:
1655 runtime->oss.format = AFMT_U8;
1656 break;
1657 case SNDRV_MINOR_OSS_PCM_16:
1658 runtime->oss.format = AFMT_S16_LE;
1659 break;
1660 default:
1661 runtime->oss.format = AFMT_MU_LAW;
1662 }
1663 runtime->oss.channels = 1;
1664 runtime->oss.fragshift = 0;
1665 runtime->oss.maxfrags = 0;
1666 runtime->oss.subdivision = 0;
1667}
1668
1669static void snd_pcm_oss_release_substream(snd_pcm_substream_t *substream)
1670{
1671 snd_pcm_runtime_t *runtime;
1672 runtime = substream->runtime;
1673 vfree(runtime->oss.buffer);
1674 snd_pcm_oss_plugin_clear(substream);
1675 substream->oss.file = NULL;
1676 substream->oss.oss = 0;
1677}
1678
1679static int snd_pcm_oss_release_file(snd_pcm_oss_file_t *pcm_oss_file)
1680{
1681 int cidx;
1682 snd_assert(pcm_oss_file != NULL, return -ENXIO);
1683 for (cidx = 0; cidx < 2; ++cidx) {
1684 snd_pcm_substream_t *substream = pcm_oss_file->streams[cidx];
1685 snd_pcm_runtime_t *runtime;
1686 if (substream == NULL)
1687 continue;
1688 runtime = substream->runtime;
1689
1690 snd_pcm_stream_lock_irq(substream);
1691 if (snd_pcm_running(substream))
1692 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
1693 snd_pcm_stream_unlock_irq(substream);
1694 if (substream->open_flag) {
1695 if (substream->ops->hw_free != NULL)
1696 substream->ops->hw_free(substream);
1697 substream->ops->close(substream);
1698 substream->open_flag = 0;
1699 }
1700 substream->ffile = NULL;
1701 snd_pcm_oss_release_substream(substream);
1702 snd_pcm_release_substream(substream);
1703 }
1704 kfree(pcm_oss_file);
1705 return 0;
1706}
1707
1708static int snd_pcm_oss_open_file(struct file *file,
1709 snd_pcm_t *pcm,
1710 snd_pcm_oss_file_t **rpcm_oss_file,
1711 int minor,
1712 snd_pcm_oss_setup_t *psetup,
1713 snd_pcm_oss_setup_t *csetup)
1714{
1715 int err = 0;
1716 snd_pcm_oss_file_t *pcm_oss_file;
1717 snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
1718 unsigned int f_mode = file->f_mode;
1719
1720 snd_assert(rpcm_oss_file != NULL, return -EINVAL);
1721 *rpcm_oss_file = NULL;
1722
1723 pcm_oss_file = kcalloc(1, sizeof(*pcm_oss_file), GFP_KERNEL);
1724 if (pcm_oss_file == NULL)
1725 return -ENOMEM;
1726
1727 if ((f_mode & (FMODE_WRITE|FMODE_READ)) == (FMODE_WRITE|FMODE_READ) &&
1728 (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX))
1729 f_mode = FMODE_WRITE;
1730 if ((f_mode & FMODE_WRITE) && !(psetup && psetup->disable)) {
1731 if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
1732 &psubstream)) < 0) {
1733 snd_pcm_oss_release_file(pcm_oss_file);
1734 return err;
1735 }
1736 pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK] = psubstream;
1737 }
1738 if ((f_mode & FMODE_READ) && !(csetup && csetup->disable)) {
1739 if ((err = snd_pcm_open_substream(pcm, SNDRV_PCM_STREAM_CAPTURE,
1740 &csubstream)) < 0) {
1741 if (!(f_mode & FMODE_WRITE) || err != -ENODEV) {
1742 snd_pcm_oss_release_file(pcm_oss_file);
1743 return err;
1744 } else {
1745 csubstream = NULL;
1746 }
1747 }
1748 pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE] = csubstream;
1749 }
1750
1751 if (psubstream == NULL && csubstream == NULL) {
1752 snd_pcm_oss_release_file(pcm_oss_file);
1753 return -EINVAL;
1754 }
1755 if (psubstream != NULL) {
1756 psubstream->oss.file = pcm_oss_file;
1757 err = snd_pcm_hw_constraints_init(psubstream);
1758 if (err < 0) {
1759 snd_printd("snd_pcm_hw_constraint_init failed\n");
1760 snd_pcm_oss_release_file(pcm_oss_file);
1761 return err;
1762 }
1763 if ((err = psubstream->ops->open(psubstream)) < 0) {
1764 snd_pcm_oss_release_file(pcm_oss_file);
1765 return err;
1766 }
1767 psubstream->open_flag = 1;
1768 err = snd_pcm_hw_constraints_complete(psubstream);
1769 if (err < 0) {
1770 snd_printd("snd_pcm_hw_constraint_complete failed\n");
1771 snd_pcm_oss_release_file(pcm_oss_file);
1772 return err;
1773 }
1774 psubstream->ffile = file;
1775 snd_pcm_oss_init_substream(psubstream, psetup, minor);
1776 }
1777 if (csubstream != NULL) {
1778 csubstream->oss.file = pcm_oss_file;
1779 err = snd_pcm_hw_constraints_init(csubstream);
1780 if (err < 0) {
1781 snd_printd("snd_pcm_hw_constraint_init failed\n");
1782 snd_pcm_oss_release_file(pcm_oss_file);
1783 return err;
1784 }
1785 if ((err = csubstream->ops->open(csubstream)) < 0) {
1786 snd_pcm_oss_release_file(pcm_oss_file);
1787 return err;
1788 }
1789 csubstream->open_flag = 1;
1790 err = snd_pcm_hw_constraints_complete(csubstream);
1791 if (err < 0) {
1792 snd_printd("snd_pcm_hw_constraint_complete failed\n");
1793 snd_pcm_oss_release_file(pcm_oss_file);
1794 return err;
1795 }
1796 csubstream->ffile = file;
1797 snd_pcm_oss_init_substream(csubstream, csetup, minor);
1798 }
1799
1800 file->private_data = pcm_oss_file;
1801 *rpcm_oss_file = pcm_oss_file;
1802 return 0;
1803}
1804
1805
1806static int snd_pcm_oss_open(struct inode *inode, struct file *file)
1807{
1808 int minor = iminor(inode);
1809 int cardnum = SNDRV_MINOR_OSS_CARD(minor);
1810 int device;
1811 int err;
1812 char task_name[32];
1813 snd_pcm_t *pcm;
1814 snd_pcm_oss_file_t *pcm_oss_file;
1815 snd_pcm_oss_setup_t *psetup = NULL, *csetup = NULL;
1816 int nonblock;
1817 wait_queue_t wait;
1818
1819 snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO);
1820 device = SNDRV_MINOR_OSS_DEVICE(minor) == SNDRV_MINOR_OSS_PCM1 ?
1821 adsp_map[cardnum] : dsp_map[cardnum];
1822
1823 pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + device];
1824 if (pcm == NULL) {
1825 err = -ENODEV;
1826 goto __error1;
1827 }
1828 err = snd_card_file_add(pcm->card, file);
1829 if (err < 0)
1830 goto __error1;
1831 if (!try_module_get(pcm->card->module)) {
1832 err = -EFAULT;
1833 goto __error2;
1834 }
1835 if (snd_task_name(current, task_name, sizeof(task_name)) < 0) {
1836 err = -EFAULT;
1837 goto __error;
1838 }
1839 if (file->f_mode & FMODE_WRITE)
1840 psetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_PLAYBACK, task_name);
1841 if (file->f_mode & FMODE_READ)
1842 csetup = snd_pcm_oss_look_for_setup(pcm, SNDRV_PCM_STREAM_CAPTURE, task_name);
1843
1844 nonblock = !!(file->f_flags & O_NONBLOCK);
1845 if (psetup && !psetup->disable) {
1846 if (psetup->nonblock)
1847 nonblock = 1;
1848 else if (psetup->block)
1849 nonblock = 0;
1850 } else if (csetup && !csetup->disable) {
1851 if (csetup->nonblock)
1852 nonblock = 1;
1853 else if (csetup->block)
1854 nonblock = 0;
1855 }
1856 if (!nonblock)
1857 nonblock = nonblock_open;
1858
1859 init_waitqueue_entry(&wait, current);
1860 add_wait_queue(&pcm->open_wait, &wait);
1861 down(&pcm->open_mutex);
1862 while (1) {
1863 err = snd_pcm_oss_open_file(file, pcm, &pcm_oss_file,
1864 minor, psetup, csetup);
1865 if (err >= 0)
1866 break;
1867 if (err == -EAGAIN) {
1868 if (nonblock) {
1869 err = -EBUSY;
1870 break;
1871 }
1872 } else
1873 break;
1874 set_current_state(TASK_INTERRUPTIBLE);
1875 up(&pcm->open_mutex);
1876 schedule();
1877 down(&pcm->open_mutex);
1878 if (signal_pending(current)) {
1879 err = -ERESTARTSYS;
1880 break;
1881 }
1882 }
1883 remove_wait_queue(&pcm->open_wait, &wait);
1884 up(&pcm->open_mutex);
1885 if (err < 0)
1886 goto __error;
1887 return err;
1888
1889 __error:
1890 module_put(pcm->card->module);
1891 __error2:
1892 snd_card_file_remove(pcm->card, file);
1893 __error1:
1894 return err;
1895}
1896
1897static int snd_pcm_oss_release(struct inode *inode, struct file *file)
1898{
1899 snd_pcm_t *pcm;
1900 snd_pcm_substream_t *substream;
1901 snd_pcm_oss_file_t *pcm_oss_file;
1902
1903 pcm_oss_file = file->private_data;
1904 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
1905 if (substream == NULL)
1906 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
1907 snd_assert(substream != NULL, return -ENXIO);
1908 pcm = substream->pcm;
1909 snd_pcm_oss_sync(pcm_oss_file);
1910 down(&pcm->open_mutex);
1911 snd_pcm_oss_release_file(pcm_oss_file);
1912 up(&pcm->open_mutex);
1913 wake_up(&pcm->open_wait);
1914 module_put(pcm->card->module);
1915 snd_card_file_remove(pcm->card, file);
1916 return 0;
1917}
1918
1919static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1920{
1921 snd_pcm_oss_file_t *pcm_oss_file;
1922 int __user *p = (int __user *)arg;
1923 int res;
1924
1925 pcm_oss_file = file->private_data;
1926 if (cmd == OSS_GETVERSION)
1927 return put_user(SNDRV_OSS_VERSION, p);
1928 if (cmd == OSS_ALSAEMULVER)
1929 return put_user(1, p);
1930#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE))
1931 if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */
1932 snd_pcm_substream_t *substream;
1933 int idx;
1934 for (idx = 0; idx < 2; ++idx) {
1935 substream = pcm_oss_file->streams[idx];
1936 if (substream != NULL)
1937 break;
1938 }
1939 snd_assert(substream != NULL, return -ENXIO);
1940 return snd_mixer_oss_ioctl_card(substream->pcm->card, cmd, arg);
1941 }
1942#endif
1943 if (((cmd >> 8) & 0xff) != 'P')
1944 return -EINVAL;
1945#ifdef OSS_DEBUG
1946 printk("pcm_oss: ioctl = 0x%x\n", cmd);
1947#endif
1948 switch (cmd) {
1949 case SNDCTL_DSP_RESET:
1950 return snd_pcm_oss_reset(pcm_oss_file);
1951 case SNDCTL_DSP_SYNC:
1952 return snd_pcm_oss_sync(pcm_oss_file);
1953 case SNDCTL_DSP_SPEED:
1954 if (get_user(res, p))
1955 return -EFAULT;
1956 if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0)
1957 return res;
1958 return put_user(res, p);
1959 case SOUND_PCM_READ_RATE:
1960 res = snd_pcm_oss_get_rate(pcm_oss_file);
1961 if (res < 0)
1962 return res;
1963 return put_user(res, p);
1964 case SNDCTL_DSP_STEREO:
1965 if (get_user(res, p))
1966 return -EFAULT;
1967 res = res > 0 ? 2 : 1;
1968 if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0)
1969 return res;
1970 return put_user(--res, p);
1971 case SNDCTL_DSP_GETBLKSIZE:
1972 res = snd_pcm_oss_get_block_size(pcm_oss_file);
1973 if (res < 0)
1974 return res;
1975 return put_user(res, p);
1976 case SNDCTL_DSP_SETFMT:
1977 if (get_user(res, p))
1978 return -EFAULT;
1979 res = snd_pcm_oss_set_format(pcm_oss_file, res);
1980 if (res < 0)
1981 return res;
1982 return put_user(res, p);
1983 case SOUND_PCM_READ_BITS:
1984 res = snd_pcm_oss_get_format(pcm_oss_file);
1985 if (res < 0)
1986 return res;
1987 return put_user(res, p);
1988 case SNDCTL_DSP_CHANNELS:
1989 if (get_user(res, p))
1990 return -EFAULT;
1991 res = snd_pcm_oss_set_channels(pcm_oss_file, res);
1992 if (res < 0)
1993 return res;
1994 return put_user(res, p);
1995 case SOUND_PCM_READ_CHANNELS:
1996 res = snd_pcm_oss_get_channels(pcm_oss_file);
1997 if (res < 0)
1998 return res;
1999 return put_user(res, p);
2000 case SOUND_PCM_WRITE_FILTER:
2001 case SOUND_PCM_READ_FILTER:
2002 return -EIO;
2003 case SNDCTL_DSP_POST:
2004 return snd_pcm_oss_post(pcm_oss_file);
2005 case SNDCTL_DSP_SUBDIVIDE:
2006 if (get_user(res, p))
2007 return -EFAULT;
2008 res = snd_pcm_oss_set_subdivide(pcm_oss_file, res);
2009 if (res < 0)
2010 return res;
2011 return put_user(res, p);
2012 case SNDCTL_DSP_SETFRAGMENT:
2013 if (get_user(res, p))
2014 return -EFAULT;
2015 return snd_pcm_oss_set_fragment(pcm_oss_file, res);
2016 case SNDCTL_DSP_GETFMTS:
2017 res = snd_pcm_oss_get_formats(pcm_oss_file);
2018 if (res < 0)
2019 return res;
2020 return put_user(res, p);
2021 case SNDCTL_DSP_GETOSPACE:
2022 case SNDCTL_DSP_GETISPACE:
2023 return snd_pcm_oss_get_space(pcm_oss_file,
2024 cmd == SNDCTL_DSP_GETISPACE ?
2025 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2026 (struct audio_buf_info __user *) arg);
2027 case SNDCTL_DSP_NONBLOCK:
2028 return snd_pcm_oss_nonblock(file);
2029 case SNDCTL_DSP_GETCAPS:
2030 res = snd_pcm_oss_get_caps(pcm_oss_file);
2031 if (res < 0)
2032 return res;
2033 return put_user(res, p);
2034 case SNDCTL_DSP_GETTRIGGER:
2035 res = snd_pcm_oss_get_trigger(pcm_oss_file);
2036 if (res < 0)
2037 return res;
2038 return put_user(res, p);
2039 case SNDCTL_DSP_SETTRIGGER:
2040 if (get_user(res, p))
2041 return -EFAULT;
2042 return snd_pcm_oss_set_trigger(pcm_oss_file, res);
2043 case SNDCTL_DSP_GETIPTR:
2044 case SNDCTL_DSP_GETOPTR:
2045 return snd_pcm_oss_get_ptr(pcm_oss_file,
2046 cmd == SNDCTL_DSP_GETIPTR ?
2047 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2048 (struct count_info __user *) arg);
2049 case SNDCTL_DSP_MAPINBUF:
2050 case SNDCTL_DSP_MAPOUTBUF:
2051 return snd_pcm_oss_get_mapbuf(pcm_oss_file,
2052 cmd == SNDCTL_DSP_MAPINBUF ?
2053 SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK,
2054 (struct buffmem_desc __user *) arg);
2055 case SNDCTL_DSP_SETSYNCRO:
2056 /* stop DMA now.. */
2057 return 0;
2058 case SNDCTL_DSP_SETDUPLEX:
2059 if (snd_pcm_oss_get_caps(pcm_oss_file) & DSP_CAP_DUPLEX)
2060 return 0;
2061 return -EIO;
2062 case SNDCTL_DSP_GETODELAY:
2063 res = snd_pcm_oss_get_odelay(pcm_oss_file);
2064 if (res < 0) {
2065 /* it's for sure, some broken apps don't check for error codes */
2066 put_user(0, p);
2067 return res;
2068 }
2069 return put_user(res, p);
2070 case SNDCTL_DSP_PROFILE:
2071 return 0; /* silently ignore */
2072 default:
2073 snd_printd("pcm_oss: unknown command = 0x%x\n", cmd);
2074 }
2075 return -EINVAL;
2076}
2077
2078#ifdef CONFIG_COMPAT
2079/* all compatible */
2080#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl
2081#else
2082#define snd_pcm_oss_ioctl_compat NULL
2083#endif
2084
2085static ssize_t snd_pcm_oss_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
2086{
2087 snd_pcm_oss_file_t *pcm_oss_file;
2088 snd_pcm_substream_t *substream;
2089
2090 pcm_oss_file = file->private_data;
2091 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2092 if (substream == NULL)
2093 return -ENXIO;
2094#ifndef OSS_DEBUG
2095 return snd_pcm_oss_read1(substream, buf, count);
2096#else
2097 {
2098 ssize_t res = snd_pcm_oss_read1(substream, buf, count);
2099 printk("pcm_oss: read %li bytes (returned %li bytes)\n", (long)count, (long)res);
2100 return res;
2101 }
2102#endif
2103}
2104
2105static ssize_t snd_pcm_oss_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
2106{
2107 snd_pcm_oss_file_t *pcm_oss_file;
2108 snd_pcm_substream_t *substream;
2109 long result;
2110
2111 pcm_oss_file = file->private_data;
2112 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2113 if (substream == NULL)
2114 return -ENXIO;
2115 up(&file->f_dentry->d_inode->i_sem);
2116 result = snd_pcm_oss_write1(substream, buf, count);
2117 down(&file->f_dentry->d_inode->i_sem);
2118#ifdef OSS_DEBUG
2119 printk("pcm_oss: write %li bytes (wrote %li bytes)\n", (long)count, (long)result);
2120#endif
2121 return result;
2122}
2123
2124static int snd_pcm_oss_playback_ready(snd_pcm_substream_t *substream)
2125{
2126 snd_pcm_runtime_t *runtime = substream->runtime;
2127 if (atomic_read(&runtime->mmap_count))
2128 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
2129 else
2130 return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames;
2131}
2132
2133static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream)
2134{
2135 snd_pcm_runtime_t *runtime = substream->runtime;
2136 if (atomic_read(&runtime->mmap_count))
2137 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt;
2138 else
2139 return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames;
2140}
2141
2142static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
2143{
2144 snd_pcm_oss_file_t *pcm_oss_file;
2145 unsigned int mask;
2146 snd_pcm_substream_t *psubstream = NULL, *csubstream = NULL;
2147
2148 pcm_oss_file = file->private_data;
2149
2150 psubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2151 csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2152
2153 mask = 0;
2154 if (psubstream != NULL) {
2155 snd_pcm_runtime_t *runtime = psubstream->runtime;
2156 poll_wait(file, &runtime->sleep, wait);
2157 snd_pcm_stream_lock_irq(psubstream);
2158 if (runtime->status->state != SNDRV_PCM_STATE_DRAINING &&
2159 (runtime->status->state != SNDRV_PCM_STATE_RUNNING ||
2160 snd_pcm_oss_playback_ready(psubstream)))
2161 mask |= POLLOUT | POLLWRNORM;
2162 snd_pcm_stream_unlock_irq(psubstream);
2163 }
2164 if (csubstream != NULL) {
2165 snd_pcm_runtime_t *runtime = csubstream->runtime;
2166 enum sndrv_pcm_state ostate;
2167 poll_wait(file, &runtime->sleep, wait);
2168 snd_pcm_stream_lock_irq(csubstream);
2169 if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
2170 snd_pcm_oss_capture_ready(csubstream))
2171 mask |= POLLIN | POLLRDNORM;
2172 snd_pcm_stream_unlock_irq(csubstream);
2173 if (ostate != SNDRV_PCM_STATE_RUNNING && runtime->oss.trigger) {
2174 snd_pcm_oss_file_t ofile;
2175 memset(&ofile, 0, sizeof(ofile));
2176 ofile.streams[SNDRV_PCM_STREAM_CAPTURE] = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2177 runtime->oss.trigger = 0;
2178 snd_pcm_oss_set_trigger(&ofile, PCM_ENABLE_INPUT);
2179 }
2180 }
2181
2182 return mask;
2183}
2184
2185static int snd_pcm_oss_mmap(struct file *file, struct vm_area_struct *area)
2186{
2187 snd_pcm_oss_file_t *pcm_oss_file;
2188 snd_pcm_substream_t *substream = NULL;
2189 snd_pcm_runtime_t *runtime;
2190 int err;
2191
2192#ifdef OSS_DEBUG
2193 printk("pcm_oss: mmap begin\n");
2194#endif
2195 pcm_oss_file = file->private_data;
2196 switch ((area->vm_flags & (VM_READ | VM_WRITE))) {
2197 case VM_READ | VM_WRITE:
2198 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2199 if (substream)
2200 break;
2201 /* Fall through */
2202 case VM_READ:
2203 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
2204 break;
2205 case VM_WRITE:
2206 substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
2207 break;
2208 default:
2209 return -EINVAL;
2210 }
2211 /* set VM_READ access as well to fix memset() routines that do
2212 reads before writes (to improve performance) */
2213 area->vm_flags |= VM_READ;
2214 if (substream == NULL)
2215 return -ENXIO;
2216 runtime = substream->runtime;
2217 if (!(runtime->info & SNDRV_PCM_INFO_MMAP_VALID))
2218 return -EIO;
2219 if (runtime->info & SNDRV_PCM_INFO_INTERLEAVED)
2220 runtime->access = SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
2221 else
2222 return -EIO;
2223
2224 if (runtime->oss.params) {
2225 if ((err = snd_pcm_oss_change_params(substream)) < 0)
2226 return err;
2227 }
2228 if (runtime->oss.plugin_first != NULL)
2229 return -EIO;
2230
2231 if (area->vm_pgoff != 0)
2232 return -EINVAL;
2233
2234 err = snd_pcm_mmap_data(substream, file, area);
2235 if (err < 0)
2236 return err;
2237 runtime->oss.mmap_bytes = area->vm_end - area->vm_start;
2238 runtime->silence_threshold = 0;
2239 runtime->silence_size = 0;
2240#ifdef OSS_DEBUG
2241 printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes);
2242#endif
2243 /* In mmap mode we never stop */
2244 runtime->stop_threshold = runtime->boundary;
2245
2246 return 0;
2247}
2248
2249/*
2250 * /proc interface
2251 */
2252
2253static void snd_pcm_oss_proc_read(snd_info_entry_t *entry,
2254 snd_info_buffer_t * buffer)
2255{
2256 snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
2257 snd_pcm_oss_setup_t *setup = pstr->oss.setup_list;
2258 down(&pstr->oss.setup_mutex);
2259 while (setup) {
2260 snd_iprintf(buffer, "%s %u %u%s%s%s%s%s%s\n",
2261 setup->task_name,
2262 setup->periods,
2263 setup->period_size,
2264 setup->disable ? " disable" : "",
2265 setup->direct ? " direct" : "",
2266 setup->block ? " block" : "",
2267 setup->nonblock ? " non-block" : "",
2268 setup->partialfrag ? " partial-frag" : "",
2269 setup->nosilence ? " no-silence" : "");
2270 setup = setup->next;
2271 }
2272 up(&pstr->oss.setup_mutex);
2273}
2274
2275static void snd_pcm_oss_proc_free_setup_list(snd_pcm_str_t * pstr)
2276{
2277 unsigned int idx;
2278 snd_pcm_substream_t *substream;
2279 snd_pcm_oss_setup_t *setup, *setupn;
2280
2281 for (idx = 0, substream = pstr->substream;
2282 idx < pstr->substream_count; idx++, substream = substream->next)
2283 substream->oss.setup = NULL;
2284 for (setup = pstr->oss.setup_list, pstr->oss.setup_list = NULL;
2285 setup; setup = setupn) {
2286 setupn = setup->next;
2287 kfree(setup->task_name);
2288 kfree(setup);
2289 }
2290 pstr->oss.setup_list = NULL;
2291}
2292
2293static void snd_pcm_oss_proc_write(snd_info_entry_t *entry,
2294 snd_info_buffer_t * buffer)
2295{
2296 snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
2297 char line[128], str[32], task_name[32], *ptr;
2298 int idx1;
2299 snd_pcm_oss_setup_t *setup, *setup1, template;
2300
2301 while (!snd_info_get_line(buffer, line, sizeof(line))) {
2302 down(&pstr->oss.setup_mutex);
2303 memset(&template, 0, sizeof(template));
2304 ptr = snd_info_get_str(task_name, line, sizeof(task_name));
2305 if (!strcmp(task_name, "clear") || !strcmp(task_name, "erase")) {
2306 snd_pcm_oss_proc_free_setup_list(pstr);
2307 up(&pstr->oss.setup_mutex);
2308 continue;
2309 }
2310 for (setup = pstr->oss.setup_list; setup; setup = setup->next) {
2311 if (!strcmp(setup->task_name, task_name)) {
2312 template = *setup;
2313 break;
2314 }
2315 }
2316 ptr = snd_info_get_str(str, ptr, sizeof(str));
2317 template.periods = simple_strtoul(str, NULL, 10);
2318 ptr = snd_info_get_str(str, ptr, sizeof(str));
2319 template.period_size = simple_strtoul(str, NULL, 10);
2320 for (idx1 = 31; idx1 >= 0; idx1--)
2321 if (template.period_size & (1 << idx1))
2322 break;
2323 for (idx1--; idx1 >= 0; idx1--)
2324 template.period_size &= ~(1 << idx1);
2325 do {
2326 ptr = snd_info_get_str(str, ptr, sizeof(str));
2327 if (!strcmp(str, "disable")) {
2328 template.disable = 1;
2329 } else if (!strcmp(str, "direct")) {
2330 template.direct = 1;
2331 } else if (!strcmp(str, "block")) {
2332 template.block = 1;
2333 } else if (!strcmp(str, "non-block")) {
2334 template.nonblock = 1;
2335 } else if (!strcmp(str, "partial-frag")) {
2336 template.partialfrag = 1;
2337 } else if (!strcmp(str, "no-silence")) {
2338 template.nosilence = 1;
2339 }
2340 } while (*str);
2341 if (setup == NULL) {
2342 setup = (snd_pcm_oss_setup_t *) kmalloc(sizeof(snd_pcm_oss_setup_t), GFP_KERNEL);
2343 if (setup) {
2344 if (pstr->oss.setup_list == NULL) {
2345 pstr->oss.setup_list = setup;
2346 } else {
2347 for (setup1 = pstr->oss.setup_list; setup1->next; setup1 = setup1->next);
2348 setup1->next = setup;
2349 }
2350 template.task_name = snd_kmalloc_strdup(task_name, GFP_KERNEL);
2351 } else {
2352 buffer->error = -ENOMEM;
2353 }
2354 }
2355 if (setup)
2356 *setup = template;
2357 up(&pstr->oss.setup_mutex);
2358 }
2359}
2360
2361static void snd_pcm_oss_proc_init(snd_pcm_t *pcm)
2362{
2363 int stream;
2364 for (stream = 0; stream < 2; ++stream) {
2365 snd_info_entry_t *entry;
2366 snd_pcm_str_t *pstr = &pcm->streams[stream];
2367 if (pstr->substream_count == 0)
2368 continue;
2369 if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
2370 entry->content = SNDRV_INFO_CONTENT_TEXT;
2371 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
2372 entry->c.text.read_size = 8192;
2373 entry->c.text.read = snd_pcm_oss_proc_read;
2374 entry->c.text.write_size = 8192;
2375 entry->c.text.write = snd_pcm_oss_proc_write;
2376 entry->private_data = pstr;
2377 if (snd_info_register(entry) < 0) {
2378 snd_info_free_entry(entry);
2379 entry = NULL;
2380 }
2381 }
2382 pstr->oss.proc_entry = entry;
2383 }
2384}
2385
2386static void snd_pcm_oss_proc_done(snd_pcm_t *pcm)
2387{
2388 int stream;
2389 for (stream = 0; stream < 2; ++stream) {
2390 snd_pcm_str_t *pstr = &pcm->streams[stream];
2391 if (pstr->oss.proc_entry) {
2392 snd_info_unregister(pstr->oss.proc_entry);
2393 pstr->oss.proc_entry = NULL;
2394 snd_pcm_oss_proc_free_setup_list(pstr);
2395 }
2396 }
2397}
2398
2399/*
2400 * ENTRY functions
2401 */
2402
2403static struct file_operations snd_pcm_oss_f_reg =
2404{
2405 .owner = THIS_MODULE,
2406 .read = snd_pcm_oss_read,
2407 .write = snd_pcm_oss_write,
2408 .open = snd_pcm_oss_open,
2409 .release = snd_pcm_oss_release,
2410 .poll = snd_pcm_oss_poll,
2411 .unlocked_ioctl = snd_pcm_oss_ioctl,
2412 .compat_ioctl = snd_pcm_oss_ioctl_compat,
2413 .mmap = snd_pcm_oss_mmap,
2414};
2415
2416static snd_minor_t snd_pcm_oss_reg =
2417{
2418 .comment = "digital audio",
2419 .f_ops = &snd_pcm_oss_f_reg,
2420};
2421
2422static void register_oss_dsp(snd_pcm_t *pcm, int index)
2423{
2424 char name[128];
2425 sprintf(name, "dsp%i%i", pcm->card->number, pcm->device);
2426 if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2427 pcm->card, index, &snd_pcm_oss_reg,
2428 name) < 0) {
2429 snd_printk("unable to register OSS PCM device %i:%i\n", pcm->card->number, pcm->device);
2430 }
2431}
2432
2433static int snd_pcm_oss_register_minor(snd_pcm_t * pcm)
2434{
2435 pcm->oss.reg = 0;
2436 if (dsp_map[pcm->card->number] == (int)pcm->device) {
2437 char name[128];
2438 int duplex;
2439 register_oss_dsp(pcm, 0);
2440 duplex = (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count > 0 &&
2441 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count &&
2442 !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
2443 sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : "");
2444#ifdef SNDRV_OSS_INFO_DEV_AUDIO
2445 snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO,
2446 pcm->card->number,
2447 name);
2448#endif
2449 pcm->oss.reg++;
2450 pcm->oss.reg_mask |= 1;
2451 }
2452 if (adsp_map[pcm->card->number] == (int)pcm->device) {
2453 register_oss_dsp(pcm, 1);
2454 pcm->oss.reg++;
2455 pcm->oss.reg_mask |= 2;
2456 }
2457
2458 if (pcm->oss.reg)
2459 snd_pcm_oss_proc_init(pcm);
2460
2461 return 0;
2462}
2463
2464static int snd_pcm_oss_disconnect_minor(snd_pcm_t * pcm)
2465{
2466 if (pcm->oss.reg) {
2467 if (pcm->oss.reg_mask & 1) {
2468 pcm->oss.reg_mask &= ~1;
2469 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2470 pcm->card, 0);
2471 }
2472 if (pcm->oss.reg_mask & 2) {
2473 pcm->oss.reg_mask &= ~2;
2474 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
2475 pcm->card, 1);
2476 }
2477 }
2478 return 0;
2479}
2480
2481static int snd_pcm_oss_unregister_minor(snd_pcm_t * pcm)
2482{
2483 snd_pcm_oss_disconnect_minor(pcm);
2484 if (pcm->oss.reg) {
2485 if (dsp_map[pcm->card->number] == (int)pcm->device) {
2486#ifdef SNDRV_OSS_INFO_DEV_AUDIO
2487 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
2488#endif
2489 }
2490 pcm->oss.reg = 0;
2491 snd_pcm_oss_proc_done(pcm);
2492 }
2493 return 0;
2494}
2495
2496static snd_pcm_notify_t snd_pcm_oss_notify =
2497{
2498 .n_register = snd_pcm_oss_register_minor,
2499 .n_disconnect = snd_pcm_oss_disconnect_minor,
2500 .n_unregister = snd_pcm_oss_unregister_minor,
2501};
2502
2503static int __init alsa_pcm_oss_init(void)
2504{
2505 int i;
2506 int err;
2507
2508 /* check device map table */
2509 for (i = 0; i < SNDRV_CARDS; i++) {
2510 if (dsp_map[i] < 0 || dsp_map[i] >= SNDRV_PCM_DEVICES) {
2511 snd_printk("invalid dsp_map[%d] = %d\n", i, dsp_map[i]);
2512 dsp_map[i] = 0;
2513 }
2514 if (adsp_map[i] < 0 || adsp_map[i] >= SNDRV_PCM_DEVICES) {
2515 snd_printk("invalid adsp_map[%d] = %d\n", i, adsp_map[i]);
2516 adsp_map[i] = 1;
2517 }
2518 }
2519 if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
2520 return err;
2521 return 0;
2522}
2523
2524static void __exit alsa_pcm_oss_exit(void)
2525{
2526 snd_pcm_notify(&snd_pcm_oss_notify, 1);
2527}
2528
2529module_init(alsa_pcm_oss_init)
2530module_exit(alsa_pcm_oss_exit)
diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c
new file mode 100644
index 000000000000..6bb31009f0b4
--- /dev/null
+++ b/sound/core/oss/pcm_plugin.c
@@ -0,0 +1,921 @@
1/*
2 * PCM Plug-In shared (kernel/library) code
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#if 0
24#define PLUGIN_DEBUG
25#endif
26
27#include <sound/driver.h>
28#include <linux/slab.h>
29#include <linux/time.h>
30#include <linux/vmalloc.h>
31#include <sound/core.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include "pcm_plugin.h"
35
36#define snd_pcm_plug_first(plug) ((plug)->runtime->oss.plugin_first)
37#define snd_pcm_plug_last(plug) ((plug)->runtime->oss.plugin_last)
38
39static int snd_pcm_plugin_src_channels_mask(snd_pcm_plugin_t *plugin,
40 bitset_t *dst_vmask,
41 bitset_t **src_vmask)
42{
43 bitset_t *vmask = plugin->src_vmask;
44 bitset_copy(vmask, dst_vmask, plugin->src_format.channels);
45 *src_vmask = vmask;
46 return 0;
47}
48
49static int snd_pcm_plugin_dst_channels_mask(snd_pcm_plugin_t *plugin,
50 bitset_t *src_vmask,
51 bitset_t **dst_vmask)
52{
53 bitset_t *vmask = plugin->dst_vmask;
54 bitset_copy(vmask, src_vmask, plugin->dst_format.channels);
55 *dst_vmask = vmask;
56 return 0;
57}
58
59/*
60 * because some cards might have rates "very close", we ignore
61 * all "resampling" requests within +-5%
62 */
63static int rate_match(unsigned int src_rate, unsigned int dst_rate)
64{
65 unsigned int low = (src_rate * 95) / 100;
66 unsigned int high = (src_rate * 105) / 100;
67 return dst_rate >= low && dst_rate <= high;
68}
69
70static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
71{
72 snd_pcm_plugin_format_t *format;
73 ssize_t width;
74 size_t size;
75 unsigned int channel;
76 snd_pcm_plugin_channel_t *c;
77
78 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) {
79 format = &plugin->src_format;
80 } else {
81 format = &plugin->dst_format;
82 }
83 if ((width = snd_pcm_format_physical_width(format->format)) < 0)
84 return width;
85 size = frames * format->channels * width;
86 snd_assert((size % 8) == 0, return -ENXIO);
87 size /= 8;
88 if (plugin->buf_frames < frames) {
89 vfree(plugin->buf);
90 plugin->buf = vmalloc(size);
91 plugin->buf_frames = frames;
92 }
93 if (!plugin->buf) {
94 plugin->buf_frames = 0;
95 return -ENOMEM;
96 }
97 c = plugin->buf_channels;
98 if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) {
99 for (channel = 0; channel < format->channels; channel++, c++) {
100 c->frames = frames;
101 c->enabled = 1;
102 c->wanted = 0;
103 c->area.addr = plugin->buf;
104 c->area.first = channel * width;
105 c->area.step = format->channels * width;
106 }
107 } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) {
108 snd_assert((size % format->channels) == 0,);
109 size /= format->channels;
110 for (channel = 0; channel < format->channels; channel++, c++) {
111 c->frames = frames;
112 c->enabled = 1;
113 c->wanted = 0;
114 c->area.addr = plugin->buf + (channel * size);
115 c->area.first = 0;
116 c->area.step = width;
117 }
118 } else
119 return -EINVAL;
120 return 0;
121}
122
123int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t frames)
124{
125 int err;
126 snd_assert(snd_pcm_plug_first(plug) != NULL, return -ENXIO);
127 if (snd_pcm_plug_stream(plug) == SNDRV_PCM_STREAM_PLAYBACK) {
128 snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
129 while (plugin->next) {
130 if (plugin->dst_frames)
131 frames = plugin->dst_frames(plugin, frames);
132 snd_assert(frames > 0, return -ENXIO);
133 plugin = plugin->next;
134 err = snd_pcm_plugin_alloc(plugin, frames);
135 if (err < 0)
136 return err;
137 }
138 } else {
139 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
140 while (plugin->prev) {
141 if (plugin->src_frames)
142 frames = plugin->src_frames(plugin, frames);
143 snd_assert(frames > 0, return -ENXIO);
144 plugin = plugin->prev;
145 err = snd_pcm_plugin_alloc(plugin, frames);
146 if (err < 0)
147 return err;
148 }
149 }
150 return 0;
151}
152
153
154snd_pcm_sframes_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
155 snd_pcm_uframes_t frames,
156 snd_pcm_plugin_channel_t **channels)
157{
158 *channels = plugin->buf_channels;
159 return frames;
160}
161
162int snd_pcm_plugin_build(snd_pcm_plug_t *plug,
163 const char *name,
164 snd_pcm_plugin_format_t *src_format,
165 snd_pcm_plugin_format_t *dst_format,
166 size_t extra,
167 snd_pcm_plugin_t **ret)
168{
169 snd_pcm_plugin_t *plugin;
170 unsigned int channels;
171
172 snd_assert(plug != NULL, return -ENXIO);
173 snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO);
174 plugin = kcalloc(1, sizeof(*plugin) + extra, GFP_KERNEL);
175 if (plugin == NULL)
176 return -ENOMEM;
177 plugin->name = name;
178 plugin->plug = plug;
179 plugin->stream = snd_pcm_plug_stream(plug);
180 plugin->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
181 plugin->src_format = *src_format;
182 plugin->src_width = snd_pcm_format_physical_width(src_format->format);
183 snd_assert(plugin->src_width > 0, );
184 plugin->dst_format = *dst_format;
185 plugin->dst_width = snd_pcm_format_physical_width(dst_format->format);
186 snd_assert(plugin->dst_width > 0, );
187 if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK)
188 channels = src_format->channels;
189 else
190 channels = dst_format->channels;
191 plugin->buf_channels = kcalloc(channels, sizeof(*plugin->buf_channels), GFP_KERNEL);
192 if (plugin->buf_channels == NULL) {
193 snd_pcm_plugin_free(plugin);
194 return -ENOMEM;
195 }
196 plugin->src_vmask = bitset_alloc(src_format->channels);
197 if (plugin->src_vmask == NULL) {
198 snd_pcm_plugin_free(plugin);
199 return -ENOMEM;
200 }
201 plugin->dst_vmask = bitset_alloc(dst_format->channels);
202 if (plugin->dst_vmask == NULL) {
203 snd_pcm_plugin_free(plugin);
204 return -ENOMEM;
205 }
206 plugin->client_channels = snd_pcm_plugin_client_channels;
207 plugin->src_channels_mask = snd_pcm_plugin_src_channels_mask;
208 plugin->dst_channels_mask = snd_pcm_plugin_dst_channels_mask;
209 *ret = plugin;
210 return 0;
211}
212
213int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin)
214{
215 if (! plugin)
216 return 0;
217 if (plugin->private_free)
218 plugin->private_free(plugin);
219 kfree(plugin->buf_channels);
220 vfree(plugin->buf);
221 kfree(plugin->src_vmask);
222 kfree(plugin->dst_vmask);
223 kfree(plugin);
224 return 0;
225}
226
227snd_pcm_sframes_t snd_pcm_plug_client_size(snd_pcm_plug_t *plug, snd_pcm_uframes_t drv_frames)
228{
229 snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
230 int stream = snd_pcm_plug_stream(plug);
231
232 snd_assert(plug != NULL, return -ENXIO);
233 if (drv_frames == 0)
234 return 0;
235 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
236 plugin = snd_pcm_plug_last(plug);
237 while (plugin && drv_frames > 0) {
238 plugin_prev = plugin->prev;
239 if (plugin->src_frames)
240 drv_frames = plugin->src_frames(plugin, drv_frames);
241 plugin = plugin_prev;
242 }
243 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
244 plugin = snd_pcm_plug_first(plug);
245 while (plugin && drv_frames > 0) {
246 plugin_next = plugin->next;
247 if (plugin->dst_frames)
248 drv_frames = plugin->dst_frames(plugin, drv_frames);
249 plugin = plugin_next;
250 }
251 } else
252 snd_BUG();
253 return drv_frames;
254}
255
256snd_pcm_sframes_t snd_pcm_plug_slave_size(snd_pcm_plug_t *plug, snd_pcm_uframes_t clt_frames)
257{
258 snd_pcm_plugin_t *plugin, *plugin_prev, *plugin_next;
259 snd_pcm_sframes_t frames;
260 int stream = snd_pcm_plug_stream(plug);
261
262 snd_assert(plug != NULL, return -ENXIO);
263 if (clt_frames == 0)
264 return 0;
265 frames = clt_frames;
266 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
267 plugin = snd_pcm_plug_first(plug);
268 while (plugin && frames > 0) {
269 plugin_next = plugin->next;
270 if (plugin->dst_frames) {
271 frames = plugin->dst_frames(plugin, frames);
272 if (frames < 0)
273 return frames;
274 }
275 plugin = plugin_next;
276 }
277 } else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
278 plugin = snd_pcm_plug_last(plug);
279 while (plugin) {
280 plugin_prev = plugin->prev;
281 if (plugin->src_frames) {
282 frames = plugin->src_frames(plugin, frames);
283 if (frames < 0)
284 return frames;
285 }
286 plugin = plugin_prev;
287 }
288 } else
289 snd_BUG();
290 return frames;
291}
292
293static int snd_pcm_plug_formats(snd_mask_t *mask, int format)
294{
295 snd_mask_t formats = *mask;
296 u64 linfmts = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 |
297 SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE |
298 SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE |
299 SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_S24_LE |
300 SNDRV_PCM_FMTBIT_U24_BE | SNDRV_PCM_FMTBIT_S24_BE |
301 SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE |
302 SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE);
303 snd_mask_set(&formats, SNDRV_PCM_FORMAT_MU_LAW);
304
305 if (formats.bits[0] & (u32)linfmts)
306 formats.bits[0] |= (u32)linfmts;
307 if (formats.bits[1] & (u32)(linfmts >> 32))
308 formats.bits[1] |= (u32)(linfmts >> 32);
309 return snd_mask_test(&formats, format);
310}
311
312static int preferred_formats[] = {
313 SNDRV_PCM_FORMAT_S16_LE,
314 SNDRV_PCM_FORMAT_S16_BE,
315 SNDRV_PCM_FORMAT_U16_LE,
316 SNDRV_PCM_FORMAT_U16_BE,
317 SNDRV_PCM_FORMAT_S24_LE,
318 SNDRV_PCM_FORMAT_S24_BE,
319 SNDRV_PCM_FORMAT_U24_LE,
320 SNDRV_PCM_FORMAT_U24_BE,
321 SNDRV_PCM_FORMAT_S32_LE,
322 SNDRV_PCM_FORMAT_S32_BE,
323 SNDRV_PCM_FORMAT_U32_LE,
324 SNDRV_PCM_FORMAT_U32_BE,
325 SNDRV_PCM_FORMAT_S8,
326 SNDRV_PCM_FORMAT_U8
327};
328
329int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask)
330{
331 if (snd_mask_test(format_mask, format))
332 return format;
333 if (! snd_pcm_plug_formats(format_mask, format))
334 return -EINVAL;
335 if (snd_pcm_format_linear(format)) {
336 int width = snd_pcm_format_width(format);
337 int unsignd = snd_pcm_format_unsigned(format);
338 int big = snd_pcm_format_big_endian(format);
339 int format1;
340 int wid, width1=width;
341 int dwidth1 = 8;
342 for (wid = 0; wid < 4; ++wid) {
343 int end, big1 = big;
344 for (end = 0; end < 2; ++end) {
345 int sgn, unsignd1 = unsignd;
346 for (sgn = 0; sgn < 2; ++sgn) {
347 format1 = snd_pcm_build_linear_format(width1, unsignd1, big1);
348 if (format1 >= 0 &&
349 snd_mask_test(format_mask, format1))
350 goto _found;
351 unsignd1 = !unsignd1;
352 }
353 big1 = !big1;
354 }
355 if (width1 == 32) {
356 dwidth1 = -dwidth1;
357 width1 = width;
358 }
359 width1 += dwidth1;
360 }
361 return -EINVAL;
362 _found:
363 return format1;
364 } else {
365 unsigned int i;
366 switch (format) {
367 case SNDRV_PCM_FORMAT_MU_LAW:
368 for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i) {
369 int format1 = preferred_formats[i];
370 if (snd_mask_test(format_mask, format1))
371 return format1;
372 }
373 default:
374 return -EINVAL;
375 }
376 }
377}
378
379int snd_pcm_plug_format_plugins(snd_pcm_plug_t *plug,
380 snd_pcm_hw_params_t *params,
381 snd_pcm_hw_params_t *slave_params)
382{
383 snd_pcm_plugin_format_t tmpformat;
384 snd_pcm_plugin_format_t dstformat;
385 snd_pcm_plugin_format_t srcformat;
386 int src_access, dst_access;
387 snd_pcm_plugin_t *plugin = NULL;
388 int err;
389 int stream = snd_pcm_plug_stream(plug);
390 int slave_interleaved = (params_channels(slave_params) == 1 ||
391 params_access(slave_params) == SNDRV_PCM_ACCESS_RW_INTERLEAVED);
392
393 switch (stream) {
394 case SNDRV_PCM_STREAM_PLAYBACK:
395 dstformat.format = params_format(slave_params);
396 dstformat.rate = params_rate(slave_params);
397 dstformat.channels = params_channels(slave_params);
398 srcformat.format = params_format(params);
399 srcformat.rate = params_rate(params);
400 srcformat.channels = params_channels(params);
401 src_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
402 dst_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
403 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
404 break;
405 case SNDRV_PCM_STREAM_CAPTURE:
406 dstformat.format = params_format(params);
407 dstformat.rate = params_rate(params);
408 dstformat.channels = params_channels(params);
409 srcformat.format = params_format(slave_params);
410 srcformat.rate = params_rate(slave_params);
411 srcformat.channels = params_channels(slave_params);
412 src_access = (slave_interleaved ? SNDRV_PCM_ACCESS_RW_INTERLEAVED :
413 SNDRV_PCM_ACCESS_RW_NONINTERLEAVED);
414 dst_access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
415 break;
416 default:
417 snd_BUG();
418 return -EINVAL;
419 }
420 tmpformat = srcformat;
421
422 pdprintf("srcformat: format=%i, rate=%i, channels=%i\n",
423 srcformat.format,
424 srcformat.rate,
425 srcformat.channels);
426 pdprintf("dstformat: format=%i, rate=%i, channels=%i\n",
427 dstformat.format,
428 dstformat.rate,
429 dstformat.channels);
430
431 /* Format change (linearization) */
432 if ((srcformat.format != dstformat.format ||
433 !rate_match(srcformat.rate, dstformat.rate) ||
434 srcformat.channels != dstformat.channels) &&
435 !snd_pcm_format_linear(srcformat.format)) {
436 if (snd_pcm_format_linear(dstformat.format))
437 tmpformat.format = dstformat.format;
438 else
439 tmpformat.format = SNDRV_PCM_FORMAT_S16;
440 switch (srcformat.format) {
441 case SNDRV_PCM_FORMAT_MU_LAW:
442 err = snd_pcm_plugin_build_mulaw(plug,
443 &srcformat, &tmpformat,
444 &plugin);
445 break;
446 default:
447 return -EINVAL;
448 }
449 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
450 if (err < 0)
451 return err;
452 err = snd_pcm_plugin_append(plugin);
453 if (err < 0) {
454 snd_pcm_plugin_free(plugin);
455 return err;
456 }
457 srcformat = tmpformat;
458 src_access = dst_access;
459 }
460
461 /* channels reduction */
462 if (srcformat.channels > dstformat.channels) {
463 int sv = srcformat.channels;
464 int dv = dstformat.channels;
465 route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
466 if (ttable == NULL)
467 return -ENOMEM;
468#if 1
469 if (sv == 2 && dv == 1) {
470 ttable[0] = HALF;
471 ttable[1] = HALF;
472 } else
473#endif
474 {
475 int v;
476 for (v = 0; v < dv; ++v)
477 ttable[v * sv + v] = FULL;
478 }
479 tmpformat.channels = dstformat.channels;
480 if (rate_match(srcformat.rate, dstformat.rate) &&
481 snd_pcm_format_linear(dstformat.format))
482 tmpformat.format = dstformat.format;
483 err = snd_pcm_plugin_build_route(plug,
484 &srcformat, &tmpformat,
485 ttable, &plugin);
486 kfree(ttable);
487 pdprintf("channels reduction: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
488 if (err < 0) {
489 snd_pcm_plugin_free(plugin);
490 return err;
491 }
492 err = snd_pcm_plugin_append(plugin);
493 if (err < 0) {
494 snd_pcm_plugin_free(plugin);
495 return err;
496 }
497 srcformat = tmpformat;
498 src_access = dst_access;
499 }
500
501 /* rate resampling */
502 if (!rate_match(srcformat.rate, dstformat.rate)) {
503 tmpformat.rate = dstformat.rate;
504 if (srcformat.channels == dstformat.channels &&
505 snd_pcm_format_linear(dstformat.format))
506 tmpformat.format = dstformat.format;
507 err = snd_pcm_plugin_build_rate(plug,
508 &srcformat, &tmpformat,
509 &plugin);
510 pdprintf("rate down resampling: src=%i, dst=%i returns %i\n", srcformat.rate, tmpformat.rate, err);
511 if (err < 0) {
512 snd_pcm_plugin_free(plugin);
513 return err;
514 }
515 err = snd_pcm_plugin_append(plugin);
516 if (err < 0) {
517 snd_pcm_plugin_free(plugin);
518 return err;
519 }
520 srcformat = tmpformat;
521 src_access = dst_access;
522 }
523
524 /* channels extension */
525 if (srcformat.channels < dstformat.channels) {
526 int sv = srcformat.channels;
527 int dv = dstformat.channels;
528 route_ttable_entry_t *ttable = kcalloc(dv * sv, sizeof(*ttable), GFP_KERNEL);
529 if (ttable == NULL)
530 return -ENOMEM;
531#if 0
532 {
533 int v;
534 for (v = 0; v < sv; ++v)
535 ttable[v * sv + v] = FULL;
536 }
537#else
538 {
539 /* Playback is spreaded on all channels */
540 int vd, vs;
541 for (vd = 0, vs = 0; vd < dv; ++vd) {
542 ttable[vd * sv + vs] = FULL;
543 vs++;
544 if (vs == sv)
545 vs = 0;
546 }
547 }
548#endif
549 tmpformat.channels = dstformat.channels;
550 if (snd_pcm_format_linear(dstformat.format))
551 tmpformat.format = dstformat.format;
552 err = snd_pcm_plugin_build_route(plug,
553 &srcformat, &tmpformat,
554 ttable, &plugin);
555 kfree(ttable);
556 pdprintf("channels extension: src=%i, dst=%i returns %i\n", srcformat.channels, tmpformat.channels, err);
557 if (err < 0) {
558 snd_pcm_plugin_free(plugin);
559 return err;
560 }
561 err = snd_pcm_plugin_append(plugin);
562 if (err < 0) {
563 snd_pcm_plugin_free(plugin);
564 return err;
565 }
566 srcformat = tmpformat;
567 src_access = dst_access;
568 }
569
570 /* format change */
571 if (srcformat.format != dstformat.format) {
572 tmpformat.format = dstformat.format;
573 if (tmpformat.format == SNDRV_PCM_FORMAT_MU_LAW) {
574 err = snd_pcm_plugin_build_mulaw(plug,
575 &srcformat, &tmpformat,
576 &plugin);
577 }
578 else if (snd_pcm_format_linear(srcformat.format) &&
579 snd_pcm_format_linear(tmpformat.format)) {
580 err = snd_pcm_plugin_build_linear(plug,
581 &srcformat, &tmpformat,
582 &plugin);
583 }
584 else
585 return -EINVAL;
586 pdprintf("format change: src=%i, dst=%i returns %i\n", srcformat.format, tmpformat.format, err);
587 if (err < 0)
588 return err;
589 err = snd_pcm_plugin_append(plugin);
590 if (err < 0) {
591 snd_pcm_plugin_free(plugin);
592 return err;
593 }
594 srcformat = tmpformat;
595 src_access = dst_access;
596 }
597
598 /* de-interleave */
599 if (src_access != dst_access) {
600 err = snd_pcm_plugin_build_copy(plug,
601 &srcformat,
602 &tmpformat,
603 &plugin);
604 pdprintf("interleave change (copy: returns %i)\n", err);
605 if (err < 0)
606 return err;
607 err = snd_pcm_plugin_append(plugin);
608 if (err < 0) {
609 snd_pcm_plugin_free(plugin);
610 return err;
611 }
612 }
613
614 return 0;
615}
616
617snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *plug,
618 char *buf,
619 snd_pcm_uframes_t count,
620 snd_pcm_plugin_channel_t **channels)
621{
622 snd_pcm_plugin_t *plugin;
623 snd_pcm_plugin_channel_t *v;
624 snd_pcm_plugin_format_t *format;
625 int width, nchannels, channel;
626 int stream = snd_pcm_plug_stream(plug);
627
628 snd_assert(buf != NULL, return -ENXIO);
629 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
630 plugin = snd_pcm_plug_first(plug);
631 format = &plugin->src_format;
632 } else {
633 plugin = snd_pcm_plug_last(plug);
634 format = &plugin->dst_format;
635 }
636 v = plugin->buf_channels;
637 *channels = v;
638 if ((width = snd_pcm_format_physical_width(format->format)) < 0)
639 return width;
640 nchannels = format->channels;
641 snd_assert(plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || format->channels <= 1, return -ENXIO);
642 for (channel = 0; channel < nchannels; channel++, v++) {
643 v->frames = count;
644 v->enabled = 1;
645 v->wanted = (stream == SNDRV_PCM_STREAM_CAPTURE);
646 v->area.addr = buf;
647 v->area.first = channel * width;
648 v->area.step = nchannels * width;
649 }
650 return count;
651}
652
653static int snd_pcm_plug_playback_channels_mask(snd_pcm_plug_t *plug,
654 bitset_t *client_vmask)
655{
656 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
657 if (plugin == NULL) {
658 return 0;
659 } else {
660 int schannels = plugin->dst_format.channels;
661 bitset_t bs[bitset_size(schannels)];
662 bitset_t *srcmask;
663 bitset_t *dstmask = bs;
664 int err;
665 bitset_one(dstmask, schannels);
666 if (plugin == NULL) {
667 bitset_and(client_vmask, dstmask, schannels);
668 return 0;
669 }
670 while (1) {
671 err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
672 if (err < 0)
673 return err;
674 dstmask = srcmask;
675 if (plugin->prev == NULL)
676 break;
677 plugin = plugin->prev;
678 }
679 bitset_and(client_vmask, dstmask, plugin->src_format.channels);
680 return 0;
681 }
682}
683
684static int snd_pcm_plug_playback_disable_useless_channels(snd_pcm_plug_t *plug,
685 snd_pcm_plugin_channel_t *src_channels)
686{
687 snd_pcm_plugin_t *plugin = snd_pcm_plug_first(plug);
688 unsigned int nchannels = plugin->src_format.channels;
689 bitset_t bs[bitset_size(nchannels)];
690 bitset_t *srcmask = bs;
691 int err;
692 unsigned int channel;
693 for (channel = 0; channel < nchannels; channel++) {
694 if (src_channels[channel].enabled)
695 bitset_set(srcmask, channel);
696 else
697 bitset_reset(srcmask, channel);
698 }
699 err = snd_pcm_plug_playback_channels_mask(plug, srcmask);
700 if (err < 0)
701 return err;
702 for (channel = 0; channel < nchannels; channel++) {
703 if (!bitset_get(srcmask, channel))
704 src_channels[channel].enabled = 0;
705 }
706 return 0;
707}
708
709static int snd_pcm_plug_capture_disable_useless_channels(snd_pcm_plug_t *plug,
710 snd_pcm_plugin_channel_t *src_channels,
711 snd_pcm_plugin_channel_t *client_channels)
712{
713 snd_pcm_plugin_t *plugin = snd_pcm_plug_last(plug);
714 unsigned int nchannels = plugin->dst_format.channels;
715 bitset_t bs[bitset_size(nchannels)];
716 bitset_t *dstmask = bs;
717 bitset_t *srcmask;
718 int err;
719 unsigned int channel;
720 for (channel = 0; channel < nchannels; channel++) {
721 if (client_channels[channel].enabled)
722 bitset_set(dstmask, channel);
723 else
724 bitset_reset(dstmask, channel);
725 }
726 while (plugin) {
727 err = plugin->src_channels_mask(plugin, dstmask, &srcmask);
728 if (err < 0)
729 return err;
730 dstmask = srcmask;
731 plugin = plugin->prev;
732 }
733 plugin = snd_pcm_plug_first(plug);
734 nchannels = plugin->src_format.channels;
735 for (channel = 0; channel < nchannels; channel++) {
736 if (!bitset_get(dstmask, channel))
737 src_channels[channel].enabled = 0;
738 }
739 return 0;
740}
741
742snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *src_channels, snd_pcm_uframes_t size)
743{
744 snd_pcm_plugin_t *plugin, *next;
745 snd_pcm_plugin_channel_t *dst_channels;
746 int err;
747 snd_pcm_sframes_t frames = size;
748
749 if ((err = snd_pcm_plug_playback_disable_useless_channels(plug, src_channels)) < 0)
750 return err;
751
752 plugin = snd_pcm_plug_first(plug);
753 while (plugin && frames > 0) {
754 if ((next = plugin->next) != NULL) {
755 snd_pcm_sframes_t frames1 = frames;
756 if (plugin->dst_frames)
757 frames1 = plugin->dst_frames(plugin, frames);
758 if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
759 return err;
760 }
761 if (err != frames1) {
762 frames = err;
763 if (plugin->src_frames)
764 frames = plugin->src_frames(plugin, frames1);
765 }
766 } else
767 dst_channels = NULL;
768 pdprintf("write plugin: %s, %li\n", plugin->name, frames);
769 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
770 return frames;
771 src_channels = dst_channels;
772 plugin = next;
773 }
774 return snd_pcm_plug_client_size(plug, frames);
775}
776
777snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *plug, snd_pcm_plugin_channel_t *dst_channels_final, snd_pcm_uframes_t size)
778{
779 snd_pcm_plugin_t *plugin, *next;
780 snd_pcm_plugin_channel_t *src_channels, *dst_channels;
781 snd_pcm_sframes_t frames = size;
782 int err;
783
784 frames = snd_pcm_plug_slave_size(plug, frames);
785 if (frames < 0)
786 return frames;
787
788 src_channels = NULL;
789 plugin = snd_pcm_plug_first(plug);
790 while (plugin && frames > 0) {
791 if ((next = plugin->next) != NULL) {
792 if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
793 return err;
794 }
795 frames = err;
796 if (!plugin->prev) {
797 if ((err = snd_pcm_plug_capture_disable_useless_channels(plug, dst_channels, dst_channels_final)) < 0)
798 return err;
799 }
800 } else {
801 dst_channels = dst_channels_final;
802 }
803 pdprintf("read plugin: %s, %li\n", plugin->name, frames);
804 if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
805 return frames;
806 plugin = next;
807 src_channels = dst_channels;
808 }
809 return frames;
810}
811
812int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, size_t dst_offset,
813 size_t samples, int format)
814{
815 /* FIXME: sub byte resolution and odd dst_offset */
816 unsigned char *dst;
817 unsigned int dst_step;
818 int width;
819 const unsigned char *silence;
820 if (!dst_area->addr)
821 return 0;
822 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
823 width = snd_pcm_format_physical_width(format);
824 if (width <= 0)
825 return -EINVAL;
826 if (dst_area->step == (unsigned int) width && width >= 8)
827 return snd_pcm_format_set_silence(format, dst, samples);
828 silence = snd_pcm_format_silence_64(format);
829 if (! silence)
830 return -EINVAL;
831 dst_step = dst_area->step / 8;
832 if (width == 4) {
833 /* Ima ADPCM */
834 int dstbit = dst_area->first % 8;
835 int dstbit_step = dst_area->step % 8;
836 while (samples-- > 0) {
837 if (dstbit)
838 *dst &= 0xf0;
839 else
840 *dst &= 0x0f;
841 dst += dst_step;
842 dstbit += dstbit_step;
843 if (dstbit == 8) {
844 dst++;
845 dstbit = 0;
846 }
847 }
848 } else {
849 width /= 8;
850 while (samples-- > 0) {
851 memcpy(dst, silence, width);
852 dst += dst_step;
853 }
854 }
855 return 0;
856}
857
858int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_area, size_t src_offset,
859 const snd_pcm_channel_area_t *dst_area, size_t dst_offset,
860 size_t samples, int format)
861{
862 /* FIXME: sub byte resolution and odd dst_offset */
863 char *src, *dst;
864 int width;
865 int src_step, dst_step;
866 src = src_area->addr + (src_area->first + src_area->step * src_offset) / 8;
867 if (!src_area->addr)
868 return snd_pcm_area_silence(dst_area, dst_offset, samples, format);
869 dst = dst_area->addr + (dst_area->first + dst_area->step * dst_offset) / 8;
870 if (!dst_area->addr)
871 return 0;
872 width = snd_pcm_format_physical_width(format);
873 if (width <= 0)
874 return -EINVAL;
875 if (src_area->step == (unsigned int) width &&
876 dst_area->step == (unsigned int) width && width >= 8) {
877 size_t bytes = samples * width / 8;
878 memcpy(dst, src, bytes);
879 return 0;
880 }
881 src_step = src_area->step / 8;
882 dst_step = dst_area->step / 8;
883 if (width == 4) {
884 /* Ima ADPCM */
885 int srcbit = src_area->first % 8;
886 int srcbit_step = src_area->step % 8;
887 int dstbit = dst_area->first % 8;
888 int dstbit_step = dst_area->step % 8;
889 while (samples-- > 0) {
890 unsigned char srcval;
891 if (srcbit)
892 srcval = *src & 0x0f;
893 else
894 srcval = (*src & 0xf0) >> 4;
895 if (dstbit)
896 *dst = (*dst & 0xf0) | srcval;
897 else
898 *dst = (*dst & 0x0f) | (srcval << 4);
899 src += src_step;
900 srcbit += srcbit_step;
901 if (srcbit == 8) {
902 src++;
903 srcbit = 0;
904 }
905 dst += dst_step;
906 dstbit += dstbit_step;
907 if (dstbit == 8) {
908 dst++;
909 dstbit = 0;
910 }
911 }
912 } else {
913 width /= 8;
914 while (samples-- > 0) {
915 memcpy(dst, src, width);
916 src += src_step;
917 dst += dst_step;
918 }
919 }
920 return 0;
921}
diff --git a/sound/core/oss/pcm_plugin.h b/sound/core/oss/pcm_plugin.h
new file mode 100644
index 000000000000..0f86ce477490
--- /dev/null
+++ b/sound/core/oss/pcm_plugin.h
@@ -0,0 +1,250 @@
1#ifndef __PCM_PLUGIN_H
2#define __PCM_PLUGIN_H
3
4/*
5 * Digital Audio (Plugin interface) abstract layer
6 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25#ifndef ATTRIBUTE_UNUSED
26#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
27#endif
28
29typedef unsigned int bitset_t;
30
31static inline size_t bitset_size(int nbits)
32{
33 return (nbits + sizeof(bitset_t) * 8 - 1) / (sizeof(bitset_t) * 8);
34}
35
36static inline bitset_t *bitset_alloc(int nbits)
37{
38 return kcalloc(bitset_size(nbits), sizeof(bitset_t), GFP_KERNEL);
39}
40
41static inline void bitset_set(bitset_t *bitmap, unsigned int pos)
42{
43 size_t bits = sizeof(*bitmap) * 8;
44 bitmap[pos / bits] |= 1 << (pos % bits);
45}
46
47static inline void bitset_reset(bitset_t *bitmap, unsigned int pos)
48{
49 size_t bits = sizeof(*bitmap) * 8;
50 bitmap[pos / bits] &= ~(1 << (pos % bits));
51}
52
53static inline int bitset_get(bitset_t *bitmap, unsigned int pos)
54{
55 size_t bits = sizeof(*bitmap) * 8;
56 return !!(bitmap[pos / bits] & (1 << (pos % bits)));
57}
58
59static inline void bitset_copy(bitset_t *dst, bitset_t *src, unsigned int nbits)
60{
61 memcpy(dst, src, bitset_size(nbits) * sizeof(bitset_t));
62}
63
64static inline void bitset_and(bitset_t *dst, bitset_t *bs, unsigned int nbits)
65{
66 bitset_t *end = dst + bitset_size(nbits);
67 while (dst < end)
68 *dst++ &= *bs++;
69}
70
71static inline void bitset_or(bitset_t *dst, bitset_t *bs, unsigned int nbits)
72{
73 bitset_t *end = dst + bitset_size(nbits);
74 while (dst < end)
75 *dst++ |= *bs++;
76}
77
78static inline void bitset_zero(bitset_t *dst, unsigned int nbits)
79{
80 bitset_t *end = dst + bitset_size(nbits);
81 while (dst < end)
82 *dst++ = 0;
83}
84
85static inline void bitset_one(bitset_t *dst, unsigned int nbits)
86{
87 bitset_t *end = dst + bitset_size(nbits);
88 while (dst < end)
89 *dst++ = ~(bitset_t)0;
90}
91
92#define snd_pcm_plug_t snd_pcm_substream_t
93#define snd_pcm_plug_stream(plug) ((plug)->stream)
94
95typedef enum {
96 INIT = 0,
97 PREPARE = 1,
98} snd_pcm_plugin_action_t;
99
100typedef struct _snd_pcm_channel_area {
101 void *addr; /* base address of channel samples */
102 unsigned int first; /* offset to first sample in bits */
103 unsigned int step; /* samples distance in bits */
104} snd_pcm_channel_area_t;
105
106typedef struct _snd_pcm_plugin_channel {
107 void *aptr; /* pointer to the allocated area */
108 snd_pcm_channel_area_t area;
109 snd_pcm_uframes_t frames; /* allocated frames */
110 unsigned int enabled:1; /* channel need to be processed */
111 unsigned int wanted:1; /* channel is wanted */
112} snd_pcm_plugin_channel_t;
113
114typedef struct _snd_pcm_plugin_format {
115 int format;
116 unsigned int rate;
117 unsigned int channels;
118} snd_pcm_plugin_format_t;
119
120struct _snd_pcm_plugin {
121 const char *name; /* plug-in name */
122 int stream;
123 snd_pcm_plugin_format_t src_format; /* source format */
124 snd_pcm_plugin_format_t dst_format; /* destination format */
125 int src_width; /* sample width in bits */
126 int dst_width; /* sample width in bits */
127 int access;
128 snd_pcm_sframes_t (*src_frames)(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t dst_frames);
129 snd_pcm_sframes_t (*dst_frames)(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t src_frames);
130 snd_pcm_sframes_t (*client_channels)(snd_pcm_plugin_t *plugin,
131 snd_pcm_uframes_t frames,
132 snd_pcm_plugin_channel_t **channels);
133 int (*src_channels_mask)(snd_pcm_plugin_t *plugin,
134 bitset_t *dst_vmask,
135 bitset_t **src_vmask);
136 int (*dst_channels_mask)(snd_pcm_plugin_t *plugin,
137 bitset_t *src_vmask,
138 bitset_t **dst_vmask);
139 snd_pcm_sframes_t (*transfer)(snd_pcm_plugin_t *plugin,
140 const snd_pcm_plugin_channel_t *src_channels,
141 snd_pcm_plugin_channel_t *dst_channels,
142 snd_pcm_uframes_t frames);
143 int (*action)(snd_pcm_plugin_t *plugin,
144 snd_pcm_plugin_action_t action,
145 unsigned long data);
146 snd_pcm_plugin_t *prev;
147 snd_pcm_plugin_t *next;
148 snd_pcm_plug_t *plug;
149 void *private_data;
150 void (*private_free)(snd_pcm_plugin_t *plugin);
151 char *buf;
152 snd_pcm_uframes_t buf_frames;
153 snd_pcm_plugin_channel_t *buf_channels;
154 bitset_t *src_vmask;
155 bitset_t *dst_vmask;
156 char extra_data[0];
157};
158
159int snd_pcm_plugin_build(snd_pcm_plug_t *handle,
160 const char *name,
161 snd_pcm_plugin_format_t *src_format,
162 snd_pcm_plugin_format_t *dst_format,
163 size_t extra,
164 snd_pcm_plugin_t **ret);
165int snd_pcm_plugin_free(snd_pcm_plugin_t *plugin);
166int snd_pcm_plugin_clear(snd_pcm_plugin_t **first);
167int snd_pcm_plug_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t frames);
168snd_pcm_sframes_t snd_pcm_plug_client_size(snd_pcm_plug_t *handle, snd_pcm_uframes_t drv_size);
169snd_pcm_sframes_t snd_pcm_plug_slave_size(snd_pcm_plug_t *handle, snd_pcm_uframes_t clt_size);
170
171#define FULL ROUTE_PLUGIN_RESOLUTION
172#define HALF ROUTE_PLUGIN_RESOLUTION / 2
173typedef int route_ttable_entry_t;
174
175int snd_pcm_plugin_build_io(snd_pcm_plug_t *handle,
176 snd_pcm_hw_params_t *params,
177 snd_pcm_plugin_t **r_plugin);
178int snd_pcm_plugin_build_linear(snd_pcm_plug_t *handle,
179 snd_pcm_plugin_format_t *src_format,
180 snd_pcm_plugin_format_t *dst_format,
181 snd_pcm_plugin_t **r_plugin);
182int snd_pcm_plugin_build_mulaw(snd_pcm_plug_t *handle,
183 snd_pcm_plugin_format_t *src_format,
184 snd_pcm_plugin_format_t *dst_format,
185 snd_pcm_plugin_t **r_plugin);
186int snd_pcm_plugin_build_rate(snd_pcm_plug_t *handle,
187 snd_pcm_plugin_format_t *src_format,
188 snd_pcm_plugin_format_t *dst_format,
189 snd_pcm_plugin_t **r_plugin);
190int snd_pcm_plugin_build_route(snd_pcm_plug_t *handle,
191 snd_pcm_plugin_format_t *src_format,
192 snd_pcm_plugin_format_t *dst_format,
193 route_ttable_entry_t *ttable,
194 snd_pcm_plugin_t **r_plugin);
195int snd_pcm_plugin_build_copy(snd_pcm_plug_t *handle,
196 snd_pcm_plugin_format_t *src_format,
197 snd_pcm_plugin_format_t *dst_format,
198 snd_pcm_plugin_t **r_plugin);
199
200int snd_pcm_plug_format_plugins(snd_pcm_plug_t *substream,
201 snd_pcm_hw_params_t *params,
202 snd_pcm_hw_params_t *slave_params);
203
204int snd_pcm_plug_slave_format(int format, snd_mask_t *format_mask);
205
206int snd_pcm_plugin_append(snd_pcm_plugin_t *plugin);
207
208snd_pcm_sframes_t snd_pcm_plug_write_transfer(snd_pcm_plug_t *handle, snd_pcm_plugin_channel_t *src_channels, snd_pcm_uframes_t size);
209snd_pcm_sframes_t snd_pcm_plug_read_transfer(snd_pcm_plug_t *handle, snd_pcm_plugin_channel_t *dst_channels_final, snd_pcm_uframes_t size);
210
211snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(snd_pcm_plug_t *handle,
212 char *buf, snd_pcm_uframes_t count,
213 snd_pcm_plugin_channel_t **channels);
214
215snd_pcm_sframes_t snd_pcm_plugin_client_channels(snd_pcm_plugin_t *plugin,
216 snd_pcm_uframes_t frames,
217 snd_pcm_plugin_channel_t **channels);
218
219int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
220 size_t samples, int format);
221int snd_pcm_area_copy(const snd_pcm_channel_area_t *src_channel, size_t src_offset,
222 const snd_pcm_channel_area_t *dst_channel, size_t dst_offset,
223 size_t samples, int format);
224
225void *snd_pcm_plug_buf_alloc(snd_pcm_plug_t *plug, snd_pcm_uframes_t size);
226void snd_pcm_plug_buf_unlock(snd_pcm_plug_t *plug, void *ptr);
227snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t size, int in_kernel);
228snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t size, int in_kernel);
229snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel);
230snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel);
231
232
233
234#define ROUTE_PLUGIN_RESOLUTION 16
235
236int getput_index(int format);
237int copy_index(int format);
238int conv_index(int src_format, int dst_format);
239
240void zero_channel(snd_pcm_plugin_t *plugin,
241 const snd_pcm_plugin_channel_t *dst_channel,
242 size_t samples);
243
244#ifdef PLUGIN_DEBUG
245#define pdprintf( fmt, args... ) printk( "plugin: " fmt, ##args)
246#else
247#define pdprintf( fmt, args... )
248#endif
249
250#endif /* __PCM_PLUGIN_H */
diff --git a/sound/core/oss/plugin_ops.h b/sound/core/oss/plugin_ops.h
new file mode 100644
index 000000000000..0607e9566084
--- /dev/null
+++ b/sound/core/oss/plugin_ops.h
@@ -0,0 +1,536 @@
1/*
2 * Plugin sample operators with fast switch
3 * Copyright (c) 2000 by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22
23#define as_u8(ptr) (*(u_int8_t*)(ptr))
24#define as_u16(ptr) (*(u_int16_t*)(ptr))
25#define as_u32(ptr) (*(u_int32_t*)(ptr))
26#define as_u64(ptr) (*(u_int64_t*)(ptr))
27#define as_s8(ptr) (*(int8_t*)(ptr))
28#define as_s16(ptr) (*(int16_t*)(ptr))
29#define as_s32(ptr) (*(int32_t*)(ptr))
30#define as_s64(ptr) (*(int64_t*)(ptr))
31
32#ifdef COPY_LABELS
33static void *copy_labels[4] = {
34 &&copy_8,
35 &&copy_16,
36 &&copy_32,
37 &&copy_64
38};
39#endif
40
41#ifdef COPY_END
42while(0) {
43copy_8: as_s8(dst) = as_s8(src); goto COPY_END;
44copy_16: as_s16(dst) = as_s16(src); goto COPY_END;
45copy_32: as_s32(dst) = as_s32(src); goto COPY_END;
46copy_64: as_s64(dst) = as_s64(src); goto COPY_END;
47}
48#endif
49
50#ifdef CONV_LABELS
51/* src_wid src_endswap sign_toggle dst_wid dst_endswap */
52static void *conv_labels[4 * 2 * 2 * 4 * 2] = {
53 &&conv_xxx1_xxx1, /* 8h -> 8h */
54 &&conv_xxx1_xxx1, /* 8h -> 8s */
55 &&conv_xxx1_xx10, /* 8h -> 16h */
56 &&conv_xxx1_xx01, /* 8h -> 16s */
57 &&conv_xxx1_x100, /* 8h -> 24h */
58 &&conv_xxx1_001x, /* 8h -> 24s */
59 &&conv_xxx1_1000, /* 8h -> 32h */
60 &&conv_xxx1_0001, /* 8h -> 32s */
61 &&conv_xxx1_xxx9, /* 8h ^> 8h */
62 &&conv_xxx1_xxx9, /* 8h ^> 8s */
63 &&conv_xxx1_xx90, /* 8h ^> 16h */
64 &&conv_xxx1_xx09, /* 8h ^> 16s */
65 &&conv_xxx1_x900, /* 8h ^> 24h */
66 &&conv_xxx1_009x, /* 8h ^> 24s */
67 &&conv_xxx1_9000, /* 8h ^> 32h */
68 &&conv_xxx1_0009, /* 8h ^> 32s */
69 &&conv_xxx1_xxx1, /* 8s -> 8h */
70 &&conv_xxx1_xxx1, /* 8s -> 8s */
71 &&conv_xxx1_xx10, /* 8s -> 16h */
72 &&conv_xxx1_xx01, /* 8s -> 16s */
73 &&conv_xxx1_x100, /* 8s -> 24h */
74 &&conv_xxx1_001x, /* 8s -> 24s */
75 &&conv_xxx1_1000, /* 8s -> 32h */
76 &&conv_xxx1_0001, /* 8s -> 32s */
77 &&conv_xxx1_xxx9, /* 8s ^> 8h */
78 &&conv_xxx1_xxx9, /* 8s ^> 8s */
79 &&conv_xxx1_xx90, /* 8s ^> 16h */
80 &&conv_xxx1_xx09, /* 8s ^> 16s */
81 &&conv_xxx1_x900, /* 8s ^> 24h */
82 &&conv_xxx1_009x, /* 8s ^> 24s */
83 &&conv_xxx1_9000, /* 8s ^> 32h */
84 &&conv_xxx1_0009, /* 8s ^> 32s */
85 &&conv_xx12_xxx1, /* 16h -> 8h */
86 &&conv_xx12_xxx1, /* 16h -> 8s */
87 &&conv_xx12_xx12, /* 16h -> 16h */
88 &&conv_xx12_xx21, /* 16h -> 16s */
89 &&conv_xx12_x120, /* 16h -> 24h */
90 &&conv_xx12_021x, /* 16h -> 24s */
91 &&conv_xx12_1200, /* 16h -> 32h */
92 &&conv_xx12_0021, /* 16h -> 32s */
93 &&conv_xx12_xxx9, /* 16h ^> 8h */
94 &&conv_xx12_xxx9, /* 16h ^> 8s */
95 &&conv_xx12_xx92, /* 16h ^> 16h */
96 &&conv_xx12_xx29, /* 16h ^> 16s */
97 &&conv_xx12_x920, /* 16h ^> 24h */
98 &&conv_xx12_029x, /* 16h ^> 24s */
99 &&conv_xx12_9200, /* 16h ^> 32h */
100 &&conv_xx12_0029, /* 16h ^> 32s */
101 &&conv_xx12_xxx2, /* 16s -> 8h */
102 &&conv_xx12_xxx2, /* 16s -> 8s */
103 &&conv_xx12_xx21, /* 16s -> 16h */
104 &&conv_xx12_xx12, /* 16s -> 16s */
105 &&conv_xx12_x210, /* 16s -> 24h */
106 &&conv_xx12_012x, /* 16s -> 24s */
107 &&conv_xx12_2100, /* 16s -> 32h */
108 &&conv_xx12_0012, /* 16s -> 32s */
109 &&conv_xx12_xxxA, /* 16s ^> 8h */
110 &&conv_xx12_xxxA, /* 16s ^> 8s */
111 &&conv_xx12_xxA1, /* 16s ^> 16h */
112 &&conv_xx12_xx1A, /* 16s ^> 16s */
113 &&conv_xx12_xA10, /* 16s ^> 24h */
114 &&conv_xx12_01Ax, /* 16s ^> 24s */
115 &&conv_xx12_A100, /* 16s ^> 32h */
116 &&conv_xx12_001A, /* 16s ^> 32s */
117 &&conv_x123_xxx1, /* 24h -> 8h */
118 &&conv_x123_xxx1, /* 24h -> 8s */
119 &&conv_x123_xx12, /* 24h -> 16h */
120 &&conv_x123_xx21, /* 24h -> 16s */
121 &&conv_x123_x123, /* 24h -> 24h */
122 &&conv_x123_321x, /* 24h -> 24s */
123 &&conv_x123_1230, /* 24h -> 32h */
124 &&conv_x123_0321, /* 24h -> 32s */
125 &&conv_x123_xxx9, /* 24h ^> 8h */
126 &&conv_x123_xxx9, /* 24h ^> 8s */
127 &&conv_x123_xx92, /* 24h ^> 16h */
128 &&conv_x123_xx29, /* 24h ^> 16s */
129 &&conv_x123_x923, /* 24h ^> 24h */
130 &&conv_x123_329x, /* 24h ^> 24s */
131 &&conv_x123_9230, /* 24h ^> 32h */
132 &&conv_x123_0329, /* 24h ^> 32s */
133 &&conv_123x_xxx3, /* 24s -> 8h */
134 &&conv_123x_xxx3, /* 24s -> 8s */
135 &&conv_123x_xx32, /* 24s -> 16h */
136 &&conv_123x_xx23, /* 24s -> 16s */
137 &&conv_123x_x321, /* 24s -> 24h */
138 &&conv_123x_123x, /* 24s -> 24s */
139 &&conv_123x_3210, /* 24s -> 32h */
140 &&conv_123x_0123, /* 24s -> 32s */
141 &&conv_123x_xxxB, /* 24s ^> 8h */
142 &&conv_123x_xxxB, /* 24s ^> 8s */
143 &&conv_123x_xxB2, /* 24s ^> 16h */
144 &&conv_123x_xx2B, /* 24s ^> 16s */
145 &&conv_123x_xB21, /* 24s ^> 24h */
146 &&conv_123x_12Bx, /* 24s ^> 24s */
147 &&conv_123x_B210, /* 24s ^> 32h */
148 &&conv_123x_012B, /* 24s ^> 32s */
149 &&conv_1234_xxx1, /* 32h -> 8h */
150 &&conv_1234_xxx1, /* 32h -> 8s */
151 &&conv_1234_xx12, /* 32h -> 16h */
152 &&conv_1234_xx21, /* 32h -> 16s */
153 &&conv_1234_x123, /* 32h -> 24h */
154 &&conv_1234_321x, /* 32h -> 24s */
155 &&conv_1234_1234, /* 32h -> 32h */
156 &&conv_1234_4321, /* 32h -> 32s */
157 &&conv_1234_xxx9, /* 32h ^> 8h */
158 &&conv_1234_xxx9, /* 32h ^> 8s */
159 &&conv_1234_xx92, /* 32h ^> 16h */
160 &&conv_1234_xx29, /* 32h ^> 16s */
161 &&conv_1234_x923, /* 32h ^> 24h */
162 &&conv_1234_329x, /* 32h ^> 24s */
163 &&conv_1234_9234, /* 32h ^> 32h */
164 &&conv_1234_4329, /* 32h ^> 32s */
165 &&conv_1234_xxx4, /* 32s -> 8h */
166 &&conv_1234_xxx4, /* 32s -> 8s */
167 &&conv_1234_xx43, /* 32s -> 16h */
168 &&conv_1234_xx34, /* 32s -> 16s */
169 &&conv_1234_x432, /* 32s -> 24h */
170 &&conv_1234_234x, /* 32s -> 24s */
171 &&conv_1234_4321, /* 32s -> 32h */
172 &&conv_1234_1234, /* 32s -> 32s */
173 &&conv_1234_xxxC, /* 32s ^> 8h */
174 &&conv_1234_xxxC, /* 32s ^> 8s */
175 &&conv_1234_xxC3, /* 32s ^> 16h */
176 &&conv_1234_xx3C, /* 32s ^> 16s */
177 &&conv_1234_xC32, /* 32s ^> 24h */
178 &&conv_1234_23Cx, /* 32s ^> 24s */
179 &&conv_1234_C321, /* 32s ^> 32h */
180 &&conv_1234_123C, /* 32s ^> 32s */
181};
182#endif
183
184#ifdef CONV_END
185while(0) {
186conv_xxx1_xxx1: as_u8(dst) = as_u8(src); goto CONV_END;
187conv_xxx1_xx10: as_u16(dst) = (u_int16_t)as_u8(src) << 8; goto CONV_END;
188conv_xxx1_xx01: as_u16(dst) = (u_int16_t)as_u8(src); goto CONV_END;
189conv_xxx1_x100: as_u32(dst) = (u_int32_t)as_u8(src) << 16; goto CONV_END;
190conv_xxx1_001x: as_u32(dst) = (u_int32_t)as_u8(src) << 8; goto CONV_END;
191conv_xxx1_1000: as_u32(dst) = (u_int32_t)as_u8(src) << 24; goto CONV_END;
192conv_xxx1_0001: as_u32(dst) = (u_int32_t)as_u8(src); goto CONV_END;
193conv_xxx1_xxx9: as_u8(dst) = as_u8(src) ^ 0x80; goto CONV_END;
194conv_xxx1_xx90: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
195conv_xxx1_xx09: as_u16(dst) = (u_int16_t)(as_u8(src) ^ 0x80); goto CONV_END;
196conv_xxx1_x900: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 16; goto CONV_END;
197conv_xxx1_009x: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 8; goto CONV_END;
198conv_xxx1_9000: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto CONV_END;
199conv_xxx1_0009: as_u32(dst) = (u_int32_t)(as_u8(src) ^ 0x80); goto CONV_END;
200conv_xx12_xxx1: as_u8(dst) = as_u16(src) >> 8; goto CONV_END;
201conv_xx12_xx12: as_u16(dst) = as_u16(src); goto CONV_END;
202conv_xx12_xx21: as_u16(dst) = swab16(as_u16(src)); goto CONV_END;
203conv_xx12_x120: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
204conv_xx12_021x: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END;
205conv_xx12_1200: as_u32(dst) = (u_int32_t)as_u16(src) << 16; goto CONV_END;
206conv_xx12_0021: as_u32(dst) = (u_int32_t)swab16(as_u16(src)); goto CONV_END;
207conv_xx12_xxx9: as_u8(dst) = (as_u16(src) >> 8) ^ 0x80; goto CONV_END;
208conv_xx12_xx92: as_u16(dst) = as_u16(src) ^ 0x8000; goto CONV_END;
209conv_xx12_xx29: as_u16(dst) = swab16(as_u16(src)) ^ 0x80; goto CONV_END;
210conv_xx12_x920: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 8; goto CONV_END;
211conv_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80) << 8; goto CONV_END;
212conv_xx12_9200: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto CONV_END;
213conv_xx12_0029: as_u32(dst) = (u_int32_t)(swab16(as_u16(src)) ^ 0x80); goto CONV_END;
214conv_xx12_xxx2: as_u8(dst) = as_u16(src) & 0xff; goto CONV_END;
215conv_xx12_x210: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 8; goto CONV_END;
216conv_xx12_012x: as_u32(dst) = (u_int32_t)as_u16(src) << 8; goto CONV_END;
217conv_xx12_2100: as_u32(dst) = (u_int32_t)swab16(as_u16(src)) << 16; goto CONV_END;
218conv_xx12_0012: as_u32(dst) = (u_int32_t)as_u16(src); goto CONV_END;
219conv_xx12_xxxA: as_u8(dst) = (as_u16(src) ^ 0x80) & 0xff; goto CONV_END;
220conv_xx12_xxA1: as_u16(dst) = swab16(as_u16(src) ^ 0x80); goto CONV_END;
221conv_xx12_xx1A: as_u16(dst) = as_u16(src) ^ 0x80; goto CONV_END;
222conv_xx12_xA10: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 8; goto CONV_END;
223conv_xx12_01Ax: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80) << 8; goto CONV_END;
224conv_xx12_A100: as_u32(dst) = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto CONV_END;
225conv_xx12_001A: as_u32(dst) = (u_int32_t)(as_u16(src) ^ 0x80); goto CONV_END;
226conv_x123_xxx1: as_u8(dst) = as_u32(src) >> 16; goto CONV_END;
227conv_x123_xx12: as_u16(dst) = as_u32(src) >> 8; goto CONV_END;
228conv_x123_xx21: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END;
229conv_x123_x123: as_u32(dst) = as_u32(src); goto CONV_END;
230conv_x123_321x: as_u32(dst) = swab32(as_u32(src)); goto CONV_END;
231conv_x123_1230: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
232conv_x123_0321: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END;
233conv_x123_xxx9: as_u8(dst) = (as_u32(src) >> 16) ^ 0x80; goto CONV_END;
234conv_x123_xx92: as_u16(dst) = (as_u32(src) >> 8) ^ 0x8000; goto CONV_END;
235conv_x123_xx29: as_u16(dst) = swab16(as_u32(src) >> 8) ^ 0x80; goto CONV_END;
236conv_x123_x923: as_u32(dst) = as_u32(src) ^ 0x800000; goto CONV_END;
237conv_x123_329x: as_u32(dst) = swab32(as_u32(src)) ^ 0x8000; goto CONV_END;
238conv_x123_9230: as_u32(dst) = (as_u32(src) ^ 0x800000) << 8; goto CONV_END;
239conv_x123_0329: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x80; goto CONV_END;
240conv_123x_xxx3: as_u8(dst) = (as_u32(src) >> 8) & 0xff; goto CONV_END;
241conv_123x_xx32: as_u16(dst) = swab16(as_u32(src) >> 8); goto CONV_END;
242conv_123x_xx23: as_u16(dst) = (as_u32(src) >> 8) & 0xffff; goto CONV_END;
243conv_123x_x321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END;
244conv_123x_123x: as_u32(dst) = as_u32(src); goto CONV_END;
245conv_123x_3210: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END;
246conv_123x_0123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
247conv_123x_xxxB: as_u8(dst) = ((as_u32(src) >> 8) & 0xff) ^ 0x80; goto CONV_END;
248conv_123x_xxB2: as_u16(dst) = swab16((as_u32(src) >> 8) ^ 0x80); goto CONV_END;
249conv_123x_xx2B: as_u16(dst) = ((as_u32(src) >> 8) & 0xffff) ^ 0x80; goto CONV_END;
250conv_123x_xB21: as_u32(dst) = swab32(as_u32(src)) ^ 0x800000; goto CONV_END;
251conv_123x_12Bx: as_u32(dst) = as_u32(src) ^ 0x8000; goto CONV_END;
252conv_123x_B210: as_u32(dst) = swab32(as_u32(src) ^ 0x8000) << 8; goto CONV_END;
253conv_123x_012B: as_u32(dst) = (as_u32(src) >> 8) ^ 0x80; goto CONV_END;
254conv_1234_xxx1: as_u8(dst) = as_u32(src) >> 24; goto CONV_END;
255conv_1234_xx12: as_u16(dst) = as_u32(src) >> 16; goto CONV_END;
256conv_1234_xx21: as_u16(dst) = swab16(as_u32(src) >> 16); goto CONV_END;
257conv_1234_x123: as_u32(dst) = as_u32(src) >> 8; goto CONV_END;
258conv_1234_321x: as_u32(dst) = swab32(as_u32(src)) << 8; goto CONV_END;
259conv_1234_1234: as_u32(dst) = as_u32(src); goto CONV_END;
260conv_1234_4321: as_u32(dst) = swab32(as_u32(src)); goto CONV_END;
261conv_1234_xxx9: as_u8(dst) = (as_u32(src) >> 24) ^ 0x80; goto CONV_END;
262conv_1234_xx92: as_u16(dst) = (as_u32(src) >> 16) ^ 0x8000; goto CONV_END;
263conv_1234_xx29: as_u16(dst) = swab16(as_u32(src) >> 16) ^ 0x80; goto CONV_END;
264conv_1234_x923: as_u32(dst) = (as_u32(src) >> 8) ^ 0x800000; goto CONV_END;
265conv_1234_329x: as_u32(dst) = (swab32(as_u32(src)) ^ 0x80) << 8; goto CONV_END;
266conv_1234_9234: as_u32(dst) = as_u32(src) ^ 0x80000000; goto CONV_END;
267conv_1234_4329: as_u32(dst) = swab32(as_u32(src)) ^ 0x80; goto CONV_END;
268conv_1234_xxx4: as_u8(dst) = as_u32(src) & 0xff; goto CONV_END;
269conv_1234_xx43: as_u16(dst) = swab16(as_u32(src)); goto CONV_END;
270conv_1234_xx34: as_u16(dst) = as_u32(src) & 0xffff; goto CONV_END;
271conv_1234_x432: as_u32(dst) = swab32(as_u32(src)) >> 8; goto CONV_END;
272conv_1234_234x: as_u32(dst) = as_u32(src) << 8; goto CONV_END;
273conv_1234_xxxC: as_u8(dst) = (as_u32(src) & 0xff) ^ 0x80; goto CONV_END;
274conv_1234_xxC3: as_u16(dst) = swab16(as_u32(src) ^ 0x80); goto CONV_END;
275conv_1234_xx3C: as_u16(dst) = (as_u32(src) & 0xffff) ^ 0x80; goto CONV_END;
276conv_1234_xC32: as_u32(dst) = (swab32(as_u32(src)) >> 8) ^ 0x800000; goto CONV_END;
277conv_1234_23Cx: as_u32(dst) = (as_u32(src) ^ 0x80) << 8; goto CONV_END;
278conv_1234_C321: as_u32(dst) = swab32(as_u32(src) ^ 0x80); goto CONV_END;
279conv_1234_123C: as_u32(dst) = as_u32(src) ^ 0x80; goto CONV_END;
280}
281#endif
282
283#ifdef GET_S16_LABELS
284/* src_wid src_endswap unsigned */
285static void *get_s16_labels[4 * 2 * 2] = {
286 &&get_s16_xxx1_xx10, /* 8h -> 16h */
287 &&get_s16_xxx1_xx90, /* 8h ^> 16h */
288 &&get_s16_xxx1_xx10, /* 8s -> 16h */
289 &&get_s16_xxx1_xx90, /* 8s ^> 16h */
290 &&get_s16_xx12_xx12, /* 16h -> 16h */
291 &&get_s16_xx12_xx92, /* 16h ^> 16h */
292 &&get_s16_xx12_xx21, /* 16s -> 16h */
293 &&get_s16_xx12_xxA1, /* 16s ^> 16h */
294 &&get_s16_x123_xx12, /* 24h -> 16h */
295 &&get_s16_x123_xx92, /* 24h ^> 16h */
296 &&get_s16_123x_xx32, /* 24s -> 16h */
297 &&get_s16_123x_xxB2, /* 24s ^> 16h */
298 &&get_s16_1234_xx12, /* 32h -> 16h */
299 &&get_s16_1234_xx92, /* 32h ^> 16h */
300 &&get_s16_1234_xx43, /* 32s -> 16h */
301 &&get_s16_1234_xxC3, /* 32s ^> 16h */
302};
303#endif
304
305#ifdef GET_S16_END
306while(0) {
307get_s16_xxx1_xx10: sample = (u_int16_t)as_u8(src) << 8; goto GET_S16_END;
308get_s16_xxx1_xx90: sample = (u_int16_t)(as_u8(src) ^ 0x80) << 8; goto GET_S16_END;
309get_s16_xx12_xx12: sample = as_u16(src); goto GET_S16_END;
310get_s16_xx12_xx92: sample = as_u16(src) ^ 0x8000; goto GET_S16_END;
311get_s16_xx12_xx21: sample = swab16(as_u16(src)); goto GET_S16_END;
312get_s16_xx12_xxA1: sample = swab16(as_u16(src) ^ 0x80); goto GET_S16_END;
313get_s16_x123_xx12: sample = as_u32(src) >> 8; goto GET_S16_END;
314get_s16_x123_xx92: sample = (as_u32(src) >> 8) ^ 0x8000; goto GET_S16_END;
315get_s16_123x_xx32: sample = swab16(as_u32(src) >> 8); goto GET_S16_END;
316get_s16_123x_xxB2: sample = swab16((as_u32(src) >> 8) ^ 0x8000); goto GET_S16_END;
317get_s16_1234_xx12: sample = as_u32(src) >> 16; goto GET_S16_END;
318get_s16_1234_xx92: sample = (as_u32(src) >> 16) ^ 0x8000; goto GET_S16_END;
319get_s16_1234_xx43: sample = swab16(as_u32(src)); goto GET_S16_END;
320get_s16_1234_xxC3: sample = swab16(as_u32(src) ^ 0x80); goto GET_S16_END;
321}
322#endif
323
324#ifdef PUT_S16_LABELS
325/* dst_wid dst_endswap unsigned */
326static void *put_s16_labels[4 * 2 * 2] = {
327 &&put_s16_xx12_xxx1, /* 16h -> 8h */
328 &&put_s16_xx12_xxx9, /* 16h ^> 8h */
329 &&put_s16_xx12_xxx1, /* 16h -> 8s */
330 &&put_s16_xx12_xxx9, /* 16h ^> 8s */
331 &&put_s16_xx12_xx12, /* 16h -> 16h */
332 &&put_s16_xx12_xx92, /* 16h ^> 16h */
333 &&put_s16_xx12_xx21, /* 16h -> 16s */
334 &&put_s16_xx12_xx29, /* 16h ^> 16s */
335 &&put_s16_xx12_x120, /* 16h -> 24h */
336 &&put_s16_xx12_x920, /* 16h ^> 24h */
337 &&put_s16_xx12_021x, /* 16h -> 24s */
338 &&put_s16_xx12_029x, /* 16h ^> 24s */
339 &&put_s16_xx12_1200, /* 16h -> 32h */
340 &&put_s16_xx12_9200, /* 16h ^> 32h */
341 &&put_s16_xx12_0021, /* 16h -> 32s */
342 &&put_s16_xx12_0029, /* 16h ^> 32s */
343};
344#endif
345
346#ifdef PUT_S16_END
347while (0) {
348put_s16_xx12_xxx1: as_u8(dst) = sample >> 8; goto PUT_S16_END;
349put_s16_xx12_xxx9: as_u8(dst) = (sample >> 8) ^ 0x80; goto PUT_S16_END;
350put_s16_xx12_xx12: as_u16(dst) = sample; goto PUT_S16_END;
351put_s16_xx12_xx92: as_u16(dst) = sample ^ 0x8000; goto PUT_S16_END;
352put_s16_xx12_xx21: as_u16(dst) = swab16(sample); goto PUT_S16_END;
353put_s16_xx12_xx29: as_u16(dst) = swab16(sample) ^ 0x80; goto PUT_S16_END;
354put_s16_xx12_x120: as_u32(dst) = (u_int32_t)sample << 8; goto PUT_S16_END;
355put_s16_xx12_x920: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 8; goto PUT_S16_END;
356put_s16_xx12_021x: as_u32(dst) = (u_int32_t)swab16(sample) << 8; goto PUT_S16_END;
357put_s16_xx12_029x: as_u32(dst) = (u_int32_t)(swab16(sample) ^ 0x80) << 8; goto PUT_S16_END;
358put_s16_xx12_1200: as_u32(dst) = (u_int32_t)sample << 16; goto PUT_S16_END;
359put_s16_xx12_9200: as_u32(dst) = (u_int32_t)(sample ^ 0x8000) << 16; goto PUT_S16_END;
360put_s16_xx12_0021: as_u32(dst) = (u_int32_t)swab16(sample); goto PUT_S16_END;
361put_s16_xx12_0029: as_u32(dst) = (u_int32_t)swab16(sample) ^ 0x80; goto PUT_S16_END;
362}
363#endif
364
365#if 0
366#ifdef GET32_LABELS
367/* src_wid src_endswap unsigned */
368static void *get32_labels[4 * 2 * 2] = {
369 &&get32_xxx1_1000, /* 8h -> 32h */
370 &&get32_xxx1_9000, /* 8h ^> 32h */
371 &&get32_xxx1_1000, /* 8s -> 32h */
372 &&get32_xxx1_9000, /* 8s ^> 32h */
373 &&get32_xx12_1200, /* 16h -> 32h */
374 &&get32_xx12_9200, /* 16h ^> 32h */
375 &&get32_xx12_2100, /* 16s -> 32h */
376 &&get32_xx12_A100, /* 16s ^> 32h */
377 &&get32_x123_1230, /* 24h -> 32h */
378 &&get32_x123_9230, /* 24h ^> 32h */
379 &&get32_123x_3210, /* 24s -> 32h */
380 &&get32_123x_B210, /* 24s ^> 32h */
381 &&get32_1234_1234, /* 32h -> 32h */
382 &&get32_1234_9234, /* 32h ^> 32h */
383 &&get32_1234_4321, /* 32s -> 32h */
384 &&get32_1234_C321, /* 32s ^> 32h */
385};
386#endif
387
388#ifdef GET32_END
389while (0) {
390get32_xxx1_1000: sample = (u_int32_t)as_u8(src) << 24; goto GET32_END;
391get32_xxx1_9000: sample = (u_int32_t)(as_u8(src) ^ 0x80) << 24; goto GET32_END;
392get32_xx12_1200: sample = (u_int32_t)as_u16(src) << 16; goto GET32_END;
393get32_xx12_9200: sample = (u_int32_t)(as_u16(src) ^ 0x8000) << 16; goto GET32_END;
394get32_xx12_2100: sample = (u_int32_t)swab16(as_u16(src)) << 16; goto GET32_END;
395get32_xx12_A100: sample = (u_int32_t)swab16(as_u16(src) ^ 0x80) << 16; goto GET32_END;
396get32_x123_1230: sample = as_u32(src) << 8; goto GET32_END;
397get32_x123_9230: sample = (as_u32(src) << 8) ^ 0x80000000; goto GET32_END;
398get32_123x_3210: sample = swab32(as_u32(src) >> 8); goto GET32_END;
399get32_123x_B210: sample = swab32((as_u32(src) >> 8) ^ 0x80); goto GET32_END;
400get32_1234_1234: sample = as_u32(src); goto GET32_END;
401get32_1234_9234: sample = as_u32(src) ^ 0x80000000; goto GET32_END;
402get32_1234_4321: sample = swab32(as_u32(src)); goto GET32_END;
403get32_1234_C321: sample = swab32(as_u32(src) ^ 0x80); goto GET32_END;
404}
405#endif
406#endif
407
408#ifdef PUT_U32_LABELS
409/* dst_wid dst_endswap unsigned */
410static void *put_u32_labels[4 * 2 * 2] = {
411 &&put_u32_1234_xxx9, /* u32h -> s8h */
412 &&put_u32_1234_xxx1, /* u32h -> u8h */
413 &&put_u32_1234_xxx9, /* u32h -> s8s */
414 &&put_u32_1234_xxx1, /* u32h -> u8s */
415 &&put_u32_1234_xx92, /* u32h -> s16h */
416 &&put_u32_1234_xx12, /* u32h -> u16h */
417 &&put_u32_1234_xx29, /* u32h -> s16s */
418 &&put_u32_1234_xx21, /* u32h -> u16s */
419 &&put_u32_1234_x923, /* u32h -> s24h */
420 &&put_u32_1234_x123, /* u32h -> u24h */
421 &&put_u32_1234_329x, /* u32h -> s24s */
422 &&put_u32_1234_321x, /* u32h -> u24s */
423 &&put_u32_1234_9234, /* u32h -> s32h */
424 &&put_u32_1234_1234, /* u32h -> u32h */
425 &&put_u32_1234_4329, /* u32h -> s32s */
426 &&put_u32_1234_4321, /* u32h -> u32s */
427};
428#endif
429
430#ifdef PUT_U32_END
431while (0) {
432put_u32_1234_xxx1: as_u8(dst) = sample >> 24; goto PUT_U32_END;
433put_u32_1234_xxx9: as_u8(dst) = (sample >> 24) ^ 0x80; goto PUT_U32_END;
434put_u32_1234_xx12: as_u16(dst) = sample >> 16; goto PUT_U32_END;
435put_u32_1234_xx92: as_u16(dst) = (sample >> 16) ^ 0x8000; goto PUT_U32_END;
436put_u32_1234_xx21: as_u16(dst) = swab16(sample >> 16); goto PUT_U32_END;
437put_u32_1234_xx29: as_u16(dst) = swab16(sample >> 16) ^ 0x80; goto PUT_U32_END;
438put_u32_1234_x123: as_u32(dst) = sample >> 8; goto PUT_U32_END;
439put_u32_1234_x923: as_u32(dst) = (sample >> 8) ^ 0x800000; goto PUT_U32_END;
440put_u32_1234_321x: as_u32(dst) = swab32(sample) << 8; goto PUT_U32_END;
441put_u32_1234_329x: as_u32(dst) = (swab32(sample) ^ 0x80) << 8; goto PUT_U32_END;
442put_u32_1234_1234: as_u32(dst) = sample; goto PUT_U32_END;
443put_u32_1234_9234: as_u32(dst) = sample ^ 0x80000000; goto PUT_U32_END;
444put_u32_1234_4321: as_u32(dst) = swab32(sample); goto PUT_U32_END;
445put_u32_1234_4329: as_u32(dst) = swab32(sample) ^ 0x80; goto PUT_U32_END;
446}
447#endif
448
449#ifdef GET_U_LABELS
450/* width endswap unsigned*/
451static void *get_u_labels[4 * 2 * 2] = {
452 &&get_u_s8, /* s8 -> u8 */
453 &&get_u_u8, /* u8 -> u8 */
454 &&get_u_s8, /* s8 -> u8 */
455 &&get_u_u8, /* u8 -> u8 */
456 &&get_u_s16h, /* s16h -> u16h */
457 &&get_u_u16h, /* u16h -> u16h */
458 &&get_u_s16s, /* s16s -> u16h */
459 &&get_u_u16s, /* u16s -> u16h */
460 &&get_u_s24h, /* s24h -> u32h */
461 &&get_u_u24h, /* u24h -> u32h */
462 &&get_u_s24s, /* s24s -> u32h */
463 &&get_u_u24s, /* u24s -> u32h */
464 &&get_u_s32h, /* s32h -> u32h */
465 &&get_u_u32h, /* u32h -> u32h */
466 &&get_u_s32s, /* s32s -> u32h */
467 &&get_u_u32s, /* u32s -> u32h */
468};
469#endif
470
471#ifdef GET_U_END
472while (0) {
473get_u_s8: sample = as_u8(src) ^ 0x80; goto GET_U_END;
474get_u_u8: sample = as_u8(src); goto GET_U_END;
475get_u_s16h: sample = as_u16(src) ^ 0x8000; goto GET_U_END;
476get_u_u16h: sample = as_u16(src); goto GET_U_END;
477get_u_s16s: sample = swab16(as_u16(src) ^ 0x80); goto GET_U_END;
478get_u_u16s: sample = swab16(as_u16(src)); goto GET_U_END;
479get_u_s24h: sample = (as_u32(src) ^ 0x800000); goto GET_U_END;
480get_u_u24h: sample = as_u32(src); goto GET_U_END;
481get_u_s24s: sample = swab32(as_u32(src) ^ 0x800000); goto GET_U_END;
482get_u_u24s: sample = swab32(as_u32(src)); goto GET_U_END;
483get_u_s32h: sample = as_u32(src) ^ 0x80000000; goto GET_U_END;
484get_u_u32h: sample = as_u32(src); goto GET_U_END;
485get_u_s32s: sample = swab32(as_u32(src) ^ 0x80); goto GET_U_END;
486get_u_u32s: sample = swab32(as_u32(src)); goto GET_U_END;
487}
488#endif
489
490#if 0
491#ifdef PUT_LABELS
492/* width endswap unsigned */
493static void *put_labels[4 * 2 * 2] = {
494 &&put_s8, /* s8 -> s8 */
495 &&put_u8, /* u8 -> s8 */
496 &&put_s8, /* s8 -> s8 */
497 &&put_u8, /* u8 -> s8 */
498 &&put_s16h, /* s16h -> s16h */
499 &&put_u16h, /* u16h -> s16h */
500 &&put_s16s, /* s16s -> s16h */
501 &&put_u16s, /* u16s -> s16h */
502 &&put_s24h, /* s24h -> s32h */
503 &&put_u24h, /* u24h -> s32h */
504 &&put_s24s, /* s24s -> s32h */
505 &&put_u24s, /* u24s -> s32h */
506 &&put_s32h, /* s32h -> s32h */
507 &&put_u32h, /* u32h -> s32h */
508 &&put_s32s, /* s32s -> s32h */
509 &&put_u32s, /* u32s -> s32h */
510};
511#endif
512
513#ifdef PUT_END
514put_s8: as_s8(dst) = sample; goto PUT_END;
515put_u8: as_u8(dst) = sample ^ 0x80; goto PUT_END;
516put_s16h: as_s16(dst) = sample; goto PUT_END;
517put_u16h: as_u16(dst) = sample ^ 0x8000; goto PUT_END;
518put_s16s: as_s16(dst) = swab16(sample); goto PUT_END;
519put_u16s: as_u16(dst) = swab16(sample ^ 0x80); goto PUT_END;
520put_s24h: as_s24(dst) = sample & 0xffffff; goto PUT_END;
521put_u24h: as_u24(dst) = sample ^ 0x80000000; goto PUT_END;
522put_s24s: as_s24(dst) = swab32(sample & 0xffffff); goto PUT_END;
523put_u24s: as_u24(dst) = swab32(sample ^ 0x80); goto PUT_END;
524put_s32h: as_s32(dst) = sample; goto PUT_END;
525put_u32h: as_u32(dst) = sample ^ 0x80000000; goto PUT_END;
526put_s32s: as_s32(dst) = swab32(sample); goto PUT_END;
527put_u32s: as_u32(dst) = swab32(sample ^ 0x80); goto PUT_END;
528#endif
529#endif
530
531#undef as_u8
532#undef as_u16
533#undef as_u32
534#undef as_s8
535#undef as_s16
536#undef as_s32
diff --git a/sound/core/oss/rate.c b/sound/core/oss/rate.c
new file mode 100644
index 000000000000..1096ec186714
--- /dev/null
+++ b/sound/core/oss/rate.c
@@ -0,0 +1,378 @@
1/*
2 * Rate conversion Plug-In
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; 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/time.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include "pcm_plugin.h"
27
28#define SHIFT 11
29#define BITS (1<<SHIFT)
30#define R_MASK (BITS-1)
31
32/*
33 * Basic rate conversion plugin
34 */
35
36typedef struct {
37 signed short last_S1;
38 signed short last_S2;
39} rate_channel_t;
40
41typedef void (*rate_f)(snd_pcm_plugin_t *plugin,
42 const snd_pcm_plugin_channel_t *src_channels,
43 snd_pcm_plugin_channel_t *dst_channels,
44 int src_frames, int dst_frames);
45
46typedef struct rate_private_data {
47 unsigned int pitch;
48 unsigned int pos;
49 rate_f func;
50 int get, put;
51 snd_pcm_sframes_t old_src_frames, old_dst_frames;
52 rate_channel_t channels[0];
53} rate_t;
54
55static void rate_init(snd_pcm_plugin_t *plugin)
56{
57 unsigned int channel;
58 rate_t *data = (rate_t *)plugin->extra_data;
59 data->pos = 0;
60 for (channel = 0; channel < plugin->src_format.channels; channel++) {
61 data->channels[channel].last_S1 = 0;
62 data->channels[channel].last_S2 = 0;
63 }
64}
65
66static void resample_expand(snd_pcm_plugin_t *plugin,
67 const snd_pcm_plugin_channel_t *src_channels,
68 snd_pcm_plugin_channel_t *dst_channels,
69 int src_frames, int dst_frames)
70{
71 unsigned int pos = 0;
72 signed int val;
73 signed short S1, S2;
74 char *src, *dst;
75 unsigned int channel;
76 int src_step, dst_step;
77 int src_frames1, dst_frames1;
78 rate_t *data = (rate_t *)plugin->extra_data;
79 rate_channel_t *rchannels = data->channels;
80
81#define GET_S16_LABELS
82#define PUT_S16_LABELS
83#include "plugin_ops.h"
84#undef GET_S16_LABELS
85#undef PUT_S16_LABELS
86 void *get = get_s16_labels[data->get];
87 void *put = put_s16_labels[data->put];
88 signed short sample = 0;
89
90 for (channel = 0; channel < plugin->src_format.channels; channel++) {
91 pos = data->pos;
92 S1 = rchannels->last_S1;
93 S2 = rchannels->last_S2;
94 if (!src_channels[channel].enabled) {
95 if (dst_channels[channel].wanted)
96 snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format);
97 dst_channels[channel].enabled = 0;
98 continue;
99 }
100 dst_channels[channel].enabled = 1;
101 src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
102 dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
103 src_step = src_channels[channel].area.step / 8;
104 dst_step = dst_channels[channel].area.step / 8;
105 src_frames1 = src_frames;
106 dst_frames1 = dst_frames;
107 while (dst_frames1-- > 0) {
108 if (pos & ~R_MASK) {
109 pos &= R_MASK;
110 S1 = S2;
111 if (src_frames1-- > 0) {
112 goto *get;
113#define GET_S16_END after_get
114#include "plugin_ops.h"
115#undef GET_S16_END
116 after_get:
117 S2 = sample;
118 src += src_step;
119 }
120 }
121 val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
122 if (val < -32768)
123 val = -32768;
124 else if (val > 32767)
125 val = 32767;
126 sample = val;
127 goto *put;
128#define PUT_S16_END after_put
129#include "plugin_ops.h"
130#undef PUT_S16_END
131 after_put:
132 dst += dst_step;
133 pos += data->pitch;
134 }
135 rchannels->last_S1 = S1;
136 rchannels->last_S2 = S2;
137 rchannels++;
138 }
139 data->pos = pos;
140}
141
142static void resample_shrink(snd_pcm_plugin_t *plugin,
143 const snd_pcm_plugin_channel_t *src_channels,
144 snd_pcm_plugin_channel_t *dst_channels,
145 int src_frames, int dst_frames)
146{
147 unsigned int pos = 0;
148 signed int val;
149 signed short S1, S2;
150 char *src, *dst;
151 unsigned int channel;
152 int src_step, dst_step;
153 int src_frames1, dst_frames1;
154 rate_t *data = (rate_t *)plugin->extra_data;
155 rate_channel_t *rchannels = data->channels;
156
157#define GET_S16_LABELS
158#define PUT_S16_LABELS
159#include "plugin_ops.h"
160#undef GET_S16_LABELS
161#undef PUT_S16_LABELS
162 void *get = get_s16_labels[data->get];
163 void *put = put_s16_labels[data->put];
164 signed short sample = 0;
165
166 for (channel = 0; channel < plugin->src_format.channels; ++channel) {
167 pos = data->pos;
168 S1 = rchannels->last_S1;
169 S2 = rchannels->last_S2;
170 if (!src_channels[channel].enabled) {
171 if (dst_channels[channel].wanted)
172 snd_pcm_area_silence(&dst_channels[channel].area, 0, dst_frames, plugin->dst_format.format);
173 dst_channels[channel].enabled = 0;
174 continue;
175 }
176 dst_channels[channel].enabled = 1;
177 src = (char *)src_channels[channel].area.addr + src_channels[channel].area.first / 8;
178 dst = (char *)dst_channels[channel].area.addr + dst_channels[channel].area.first / 8;
179 src_step = src_channels[channel].area.step / 8;
180 dst_step = dst_channels[channel].area.step / 8;
181 src_frames1 = src_frames;
182 dst_frames1 = dst_frames;
183 while (dst_frames1 > 0) {
184 S1 = S2;
185 if (src_frames1-- > 0) {
186 goto *get;
187#define GET_S16_END after_get
188#include "plugin_ops.h"
189#undef GET_S16_END
190 after_get:
191 S2 = sample;
192 src += src_step;
193 }
194 if (pos & ~R_MASK) {
195 pos &= R_MASK;
196 val = S1 + ((S2 - S1) * (signed int)pos) / BITS;
197 if (val < -32768)
198 val = -32768;
199 else if (val > 32767)
200 val = 32767;
201 sample = val;
202 goto *put;
203#define PUT_S16_END after_put
204#include "plugin_ops.h"
205#undef PUT_S16_END
206 after_put:
207 dst += dst_step;
208 dst_frames1--;
209 }
210 pos += data->pitch;
211 }
212 rchannels->last_S1 = S1;
213 rchannels->last_S2 = S2;
214 rchannels++;
215 }
216 data->pos = pos;
217}
218
219static snd_pcm_sframes_t rate_src_frames(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
220{
221 rate_t *data;
222 snd_pcm_sframes_t res;
223
224 snd_assert(plugin != NULL, return -ENXIO);
225 if (frames == 0)
226 return 0;
227 data = (rate_t *)plugin->extra_data;
228 if (plugin->src_format.rate < plugin->dst_format.rate) {
229 res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
230 } else {
231 res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
232 }
233 if (data->old_src_frames > 0) {
234 snd_pcm_sframes_t frames1 = frames, res1 = data->old_dst_frames;
235 while (data->old_src_frames < frames1) {
236 frames1 >>= 1;
237 res1 <<= 1;
238 }
239 while (data->old_src_frames > frames1) {
240 frames1 <<= 1;
241 res1 >>= 1;
242 }
243 if (data->old_src_frames == frames1)
244 return res1;
245 }
246 data->old_src_frames = frames;
247 data->old_dst_frames = res;
248 return res;
249}
250
251static snd_pcm_sframes_t rate_dst_frames(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames)
252{
253 rate_t *data;
254 snd_pcm_sframes_t res;
255
256 snd_assert(plugin != NULL, return -ENXIO);
257 if (frames == 0)
258 return 0;
259 data = (rate_t *)plugin->extra_data;
260 if (plugin->src_format.rate < plugin->dst_format.rate) {
261 res = (((frames << SHIFT) + (data->pitch / 2)) / data->pitch);
262 } else {
263 res = (((frames * data->pitch) + (BITS/2)) >> SHIFT);
264 }
265 if (data->old_dst_frames > 0) {
266 snd_pcm_sframes_t frames1 = frames, res1 = data->old_src_frames;
267 while (data->old_dst_frames < frames1) {
268 frames1 >>= 1;
269 res1 <<= 1;
270 }
271 while (data->old_dst_frames > frames1) {
272 frames1 <<= 1;
273 res1 >>= 1;
274 }
275 if (data->old_dst_frames == frames1)
276 return res1;
277 }
278 data->old_dst_frames = frames;
279 data->old_src_frames = res;
280 return res;
281}
282
283static snd_pcm_sframes_t rate_transfer(snd_pcm_plugin_t *plugin,
284 const snd_pcm_plugin_channel_t *src_channels,
285 snd_pcm_plugin_channel_t *dst_channels,
286 snd_pcm_uframes_t frames)
287{
288 snd_pcm_uframes_t dst_frames;
289 rate_t *data;
290
291 snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
292 if (frames == 0)
293 return 0;
294#ifdef CONFIG_SND_DEBUG
295 {
296 unsigned int channel;
297 for (channel = 0; channel < plugin->src_format.channels; channel++) {
298 snd_assert(src_channels[channel].area.first % 8 == 0 &&
299 src_channels[channel].area.step % 8 == 0,
300 return -ENXIO);
301 snd_assert(dst_channels[channel].area.first % 8 == 0 &&
302 dst_channels[channel].area.step % 8 == 0,
303 return -ENXIO);
304 }
305 }
306#endif
307
308 dst_frames = rate_dst_frames(plugin, frames);
309 if (dst_frames > dst_channels[0].frames)
310 dst_frames = dst_channels[0].frames;
311 data = (rate_t *)plugin->extra_data;
312 data->func(plugin, src_channels, dst_channels, frames, dst_frames);
313 return dst_frames;
314}
315
316static int rate_action(snd_pcm_plugin_t *plugin,
317 snd_pcm_plugin_action_t action,
318 unsigned long udata ATTRIBUTE_UNUSED)
319{
320 snd_assert(plugin != NULL, return -ENXIO);
321 switch (action) {
322 case INIT:
323 case PREPARE:
324 rate_init(plugin);
325 break;
326 default:
327 break;
328 }
329 return 0; /* silenty ignore other actions */
330}
331
332int snd_pcm_plugin_build_rate(snd_pcm_plug_t *plug,
333 snd_pcm_plugin_format_t *src_format,
334 snd_pcm_plugin_format_t *dst_format,
335 snd_pcm_plugin_t **r_plugin)
336{
337 int err;
338 rate_t *data;
339 snd_pcm_plugin_t *plugin;
340
341 snd_assert(r_plugin != NULL, return -ENXIO);
342 *r_plugin = NULL;
343
344 snd_assert(src_format->channels == dst_format->channels, return -ENXIO);
345 snd_assert(src_format->channels > 0, return -ENXIO);
346 snd_assert(snd_pcm_format_linear(src_format->format) != 0, return -ENXIO);
347 snd_assert(snd_pcm_format_linear(dst_format->format) != 0, return -ENXIO);
348 snd_assert(src_format->rate != dst_format->rate, return -ENXIO);
349
350 err = snd_pcm_plugin_build(plug, "rate conversion",
351 src_format, dst_format,
352 sizeof(rate_t) + src_format->channels * sizeof(rate_channel_t),
353 &plugin);
354 if (err < 0)
355 return err;
356 data = (rate_t *)plugin->extra_data;
357 data->get = getput_index(src_format->format);
358 snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
359 data->put = getput_index(dst_format->format);
360 snd_assert(data->put >= 0 && data->put < 4*2*2, return -EINVAL);
361
362 if (src_format->rate < dst_format->rate) {
363 data->pitch = ((src_format->rate << SHIFT) + (dst_format->rate >> 1)) / dst_format->rate;
364 data->func = resample_expand;
365 } else {
366 data->pitch = ((dst_format->rate << SHIFT) + (src_format->rate >> 1)) / src_format->rate;
367 data->func = resample_shrink;
368 }
369 data->pos = 0;
370 rate_init(plugin);
371 data->old_src_frames = data->old_dst_frames = 0;
372 plugin->transfer = rate_transfer;
373 plugin->src_frames = rate_src_frames;
374 plugin->dst_frames = rate_dst_frames;
375 plugin->action = rate_action;
376 *r_plugin = plugin;
377 return 0;
378}
diff --git a/sound/core/oss/route.c b/sound/core/oss/route.c
new file mode 100644
index 000000000000..c955b7dfdb30
--- /dev/null
+++ b/sound/core/oss/route.c
@@ -0,0 +1,519 @@
1/*
2 * Attenuated route Plug-In
3 * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; 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/slab.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/pcm.h>
27#include "pcm_plugin.h"
28
29/* The best possible hack to support missing optimization in gcc 2.7.2.3 */
30#if ROUTE_PLUGIN_RESOLUTION & (ROUTE_PLUGIN_RESOLUTION - 1) != 0
31#define div(a) a /= ROUTE_PLUGIN_RESOLUTION
32#elif ROUTE_PLUGIN_RESOLUTION == 16
33#define div(a) a >>= 4
34#else
35#error "Add some code here"
36#endif
37
38typedef struct ttable_dst ttable_dst_t;
39typedef struct route_private_data route_t;
40
41typedef void (*route_channel_f)(snd_pcm_plugin_t *plugin,
42 const snd_pcm_plugin_channel_t *src_channels,
43 snd_pcm_plugin_channel_t *dst_channel,
44 ttable_dst_t* ttable, snd_pcm_uframes_t frames);
45
46typedef struct {
47 int channel;
48 int as_int;
49} ttable_src_t;
50
51struct ttable_dst {
52 int att; /* Attenuated */
53 unsigned int nsrcs;
54 ttable_src_t* srcs;
55 route_channel_f func;
56};
57
58struct route_private_data {
59 enum {R_UINT32=0, R_UINT64=1} sum_type;
60 int get, put;
61 int conv;
62 int src_sample_size;
63 ttable_dst_t ttable[0];
64};
65
66typedef union {
67 u_int32_t as_uint32;
68 u_int64_t as_uint64;
69} sum_t;
70
71
72static void route_to_channel_from_zero(snd_pcm_plugin_t *plugin,
73 const snd_pcm_plugin_channel_t *src_channels ATTRIBUTE_UNUSED,
74 snd_pcm_plugin_channel_t *dst_channel,
75 ttable_dst_t* ttable ATTRIBUTE_UNUSED, snd_pcm_uframes_t frames)
76{
77 if (dst_channel->wanted)
78 snd_pcm_area_silence(&dst_channel->area, 0, frames, plugin->dst_format.format);
79 dst_channel->enabled = 0;
80}
81
82static void route_to_channel_from_one(snd_pcm_plugin_t *plugin,
83 const snd_pcm_plugin_channel_t *src_channels,
84 snd_pcm_plugin_channel_t *dst_channel,
85 ttable_dst_t* ttable, snd_pcm_uframes_t frames)
86{
87#define CONV_LABELS
88#include "plugin_ops.h"
89#undef CONV_LABELS
90 route_t *data = (route_t *)plugin->extra_data;
91 void *conv;
92 const snd_pcm_plugin_channel_t *src_channel = NULL;
93 unsigned int srcidx;
94 char *src, *dst;
95 int src_step, dst_step;
96 for (srcidx = 0; srcidx < ttable->nsrcs; ++srcidx) {
97 src_channel = &src_channels[ttable->srcs[srcidx].channel];
98 if (src_channel->area.addr != NULL)
99 break;
100 }
101 if (srcidx == ttable->nsrcs) {
102 route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
103 return;
104 }
105
106 dst_channel->enabled = 1;
107 conv = conv_labels[data->conv];
108 src = src_channel->area.addr + src_channel->area.first / 8;
109 src_step = src_channel->area.step / 8;
110 dst = dst_channel->area.addr + dst_channel->area.first / 8;
111 dst_step = dst_channel->area.step / 8;
112 while (frames-- > 0) {
113 goto *conv;
114#define CONV_END after
115#include "plugin_ops.h"
116#undef CONV_END
117 after:
118 src += src_step;
119 dst += dst_step;
120 }
121}
122
123static void route_to_channel(snd_pcm_plugin_t *plugin,
124 const snd_pcm_plugin_channel_t *src_channels,
125 snd_pcm_plugin_channel_t *dst_channel,
126 ttable_dst_t* ttable, snd_pcm_uframes_t frames)
127{
128#define GET_U_LABELS
129#define PUT_U32_LABELS
130#include "plugin_ops.h"
131#undef GET_U_LABELS
132#undef PUT_U32_LABELS
133 static void *zero_labels[2] = { &&zero_int32, &&zero_int64 };
134 /* sum_type att */
135 static void *add_labels[2 * 2] = { &&add_int32_noatt, &&add_int32_att,
136 &&add_int64_noatt, &&add_int64_att,
137 };
138 /* sum_type att shift */
139 static void *norm_labels[2 * 2 * 4] = { NULL,
140 &&norm_int32_8_noatt,
141 &&norm_int32_16_noatt,
142 &&norm_int32_24_noatt,
143 NULL,
144 &&norm_int32_8_att,
145 &&norm_int32_16_att,
146 &&norm_int32_24_att,
147 &&norm_int64_0_noatt,
148 &&norm_int64_8_noatt,
149 &&norm_int64_16_noatt,
150 &&norm_int64_24_noatt,
151 &&norm_int64_0_att,
152 &&norm_int64_8_att,
153 &&norm_int64_16_att,
154 &&norm_int64_24_att,
155 };
156 route_t *data = (route_t *)plugin->extra_data;
157 void *zero, *get, *add, *norm, *put_u32;
158 int nsrcs = ttable->nsrcs;
159 char *dst;
160 int dst_step;
161 char *srcs[nsrcs];
162 int src_steps[nsrcs];
163 ttable_src_t src_tt[nsrcs];
164 u_int32_t sample = 0;
165 int srcidx, srcidx1 = 0;
166 for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
167 const snd_pcm_plugin_channel_t *src_channel = &src_channels[ttable->srcs[srcidx].channel];
168 if (!src_channel->enabled)
169 continue;
170 srcs[srcidx1] = src_channel->area.addr + src_channel->area.first / 8;
171 src_steps[srcidx1] = src_channel->area.step / 8;
172 src_tt[srcidx1] = ttable->srcs[srcidx];
173 srcidx1++;
174 }
175 nsrcs = srcidx1;
176 if (nsrcs == 0) {
177 route_to_channel_from_zero(plugin, src_channels, dst_channel, ttable, frames);
178 return;
179 } else if (nsrcs == 1 && src_tt[0].as_int == ROUTE_PLUGIN_RESOLUTION) {
180 route_to_channel_from_one(plugin, src_channels, dst_channel, ttable, frames);
181 return;
182 }
183
184 dst_channel->enabled = 1;
185 zero = zero_labels[data->sum_type];
186 get = get_u_labels[data->get];
187 add = add_labels[data->sum_type * 2 + ttable->att];
188 norm = norm_labels[data->sum_type * 8 + ttable->att * 4 + 4 - data->src_sample_size];
189 put_u32 = put_u32_labels[data->put];
190 dst = dst_channel->area.addr + dst_channel->area.first / 8;
191 dst_step = dst_channel->area.step / 8;
192
193 while (frames-- > 0) {
194 ttable_src_t *ttp = src_tt;
195 sum_t sum;
196
197 /* Zero sum */
198 goto *zero;
199 zero_int32:
200 sum.as_uint32 = 0;
201 goto zero_end;
202 zero_int64:
203 sum.as_uint64 = 0;
204 goto zero_end;
205 zero_end:
206 for (srcidx = 0; srcidx < nsrcs; ++srcidx) {
207 char *src = srcs[srcidx];
208
209 /* Get sample */
210 goto *get;
211#define GET_U_END after_get
212#include "plugin_ops.h"
213#undef GET_U_END
214 after_get:
215
216 /* Sum */
217 goto *add;
218 add_int32_att:
219 sum.as_uint32 += sample * ttp->as_int;
220 goto after_sum;
221 add_int32_noatt:
222 if (ttp->as_int)
223 sum.as_uint32 += sample;
224 goto after_sum;
225 add_int64_att:
226 sum.as_uint64 += (u_int64_t) sample * ttp->as_int;
227 goto after_sum;
228 add_int64_noatt:
229 if (ttp->as_int)
230 sum.as_uint64 += sample;
231 goto after_sum;
232 after_sum:
233 srcs[srcidx] += src_steps[srcidx];
234 ttp++;
235 }
236
237 /* Normalization */
238 goto *norm;
239 norm_int32_8_att:
240 sum.as_uint64 = sum.as_uint32;
241 norm_int64_8_att:
242 sum.as_uint64 <<= 8;
243 norm_int64_0_att:
244 div(sum.as_uint64);
245 goto norm_int;
246
247 norm_int32_16_att:
248 sum.as_uint64 = sum.as_uint32;
249 norm_int64_16_att:
250 sum.as_uint64 <<= 16;
251 div(sum.as_uint64);
252 goto norm_int;
253
254 norm_int32_24_att:
255 sum.as_uint64 = sum.as_uint32;
256 norm_int64_24_att:
257 sum.as_uint64 <<= 24;
258 div(sum.as_uint64);
259 goto norm_int;
260
261 norm_int32_8_noatt:
262 sum.as_uint64 = sum.as_uint32;
263 norm_int64_8_noatt:
264 sum.as_uint64 <<= 8;
265 goto norm_int;
266
267 norm_int32_16_noatt:
268 sum.as_uint64 = sum.as_uint32;
269 norm_int64_16_noatt:
270 sum.as_uint64 <<= 16;
271 goto norm_int;
272
273 norm_int32_24_noatt:
274 sum.as_uint64 = sum.as_uint32;
275 norm_int64_24_noatt:
276 sum.as_uint64 <<= 24;
277 goto norm_int;
278
279 norm_int64_0_noatt:
280 norm_int:
281 if (sum.as_uint64 > (u_int32_t)0xffffffff)
282 sample = (u_int32_t)0xffffffff;
283 else
284 sample = sum.as_uint64;
285 goto after_norm;
286
287 after_norm:
288
289 /* Put sample */
290 goto *put_u32;
291#define PUT_U32_END after_put_u32
292#include "plugin_ops.h"
293#undef PUT_U32_END
294 after_put_u32:
295
296 dst += dst_step;
297 }
298}
299
300static int route_src_channels_mask(snd_pcm_plugin_t *plugin,
301 bitset_t *dst_vmask,
302 bitset_t **src_vmask)
303{
304 route_t *data = (route_t *)plugin->extra_data;
305 int schannels = plugin->src_format.channels;
306 int dchannels = plugin->dst_format.channels;
307 bitset_t *vmask = plugin->src_vmask;
308 int channel;
309 ttable_dst_t *dp = data->ttable;
310 bitset_zero(vmask, schannels);
311 for (channel = 0; channel < dchannels; channel++, dp++) {
312 unsigned int src;
313 ttable_src_t *sp;
314 if (!bitset_get(dst_vmask, channel))
315 continue;
316 sp = dp->srcs;
317 for (src = 0; src < dp->nsrcs; src++, sp++)
318 bitset_set(vmask, sp->channel);
319 }
320 *src_vmask = vmask;
321 return 0;
322}
323
324static int route_dst_channels_mask(snd_pcm_plugin_t *plugin,
325 bitset_t *src_vmask,
326 bitset_t **dst_vmask)
327{
328 route_t *data = (route_t *)plugin->extra_data;
329 int dchannels = plugin->dst_format.channels;
330 bitset_t *vmask = plugin->dst_vmask;
331 int channel;
332 ttable_dst_t *dp = data->ttable;
333 bitset_zero(vmask, dchannels);
334 for (channel = 0; channel < dchannels; channel++, dp++) {
335 unsigned int src;
336 ttable_src_t *sp;
337 sp = dp->srcs;
338 for (src = 0; src < dp->nsrcs; src++, sp++) {
339 if (bitset_get(src_vmask, sp->channel)) {
340 bitset_set(vmask, channel);
341 break;
342 }
343 }
344 }
345 *dst_vmask = vmask;
346 return 0;
347}
348
349static void route_free(snd_pcm_plugin_t *plugin)
350{
351 route_t *data = (route_t *)plugin->extra_data;
352 unsigned int dst_channel;
353 for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
354 kfree(data->ttable[dst_channel].srcs);
355 }
356}
357
358static int route_load_ttable(snd_pcm_plugin_t *plugin,
359 const route_ttable_entry_t* src_ttable)
360{
361 route_t *data;
362 unsigned int src_channel, dst_channel;
363 const route_ttable_entry_t *sptr;
364 ttable_dst_t *dptr;
365 if (src_ttable == NULL)
366 return 0;
367 data = (route_t *)plugin->extra_data;
368 dptr = data->ttable;
369 sptr = src_ttable;
370 plugin->private_free = route_free;
371 for (dst_channel = 0; dst_channel < plugin->dst_format.channels; ++dst_channel) {
372 route_ttable_entry_t t = 0;
373 int att = 0;
374 int nsrcs = 0;
375 ttable_src_t srcs[plugin->src_format.channels];
376 for (src_channel = 0; src_channel < plugin->src_format.channels; ++src_channel) {
377 snd_assert(*sptr >= 0 || *sptr <= FULL, return -ENXIO);
378 if (*sptr != 0) {
379 srcs[nsrcs].channel = src_channel;
380 srcs[nsrcs].as_int = *sptr;
381 if (*sptr != FULL)
382 att = 1;
383 t += *sptr;
384 nsrcs++;
385 }
386 sptr++;
387 }
388 dptr->att = att;
389 dptr->nsrcs = nsrcs;
390 if (nsrcs == 0)
391 dptr->func = route_to_channel_from_zero;
392 else if (nsrcs == 1 && !att)
393 dptr->func = route_to_channel_from_one;
394 else
395 dptr->func = route_to_channel;
396 if (nsrcs > 0) {
397 int srcidx;
398 dptr->srcs = kcalloc(nsrcs, sizeof(*srcs), GFP_KERNEL);
399 for(srcidx = 0; srcidx < nsrcs; srcidx++)
400 dptr->srcs[srcidx] = srcs[srcidx];
401 } else
402 dptr->srcs = NULL;
403 dptr++;
404 }
405 return 0;
406}
407
408static snd_pcm_sframes_t route_transfer(snd_pcm_plugin_t *plugin,
409 const snd_pcm_plugin_channel_t *src_channels,
410 snd_pcm_plugin_channel_t *dst_channels,
411 snd_pcm_uframes_t frames)
412{
413 route_t *data;
414 int src_nchannels, dst_nchannels;
415 int dst_channel;
416 ttable_dst_t *ttp;
417 snd_pcm_plugin_channel_t *dvp;
418
419 snd_assert(plugin != NULL && src_channels != NULL && dst_channels != NULL, return -ENXIO);
420 if (frames == 0)
421 return 0;
422 data = (route_t *)plugin->extra_data;
423
424 src_nchannels = plugin->src_format.channels;
425 dst_nchannels = plugin->dst_format.channels;
426
427#ifdef CONFIG_SND_DEBUG
428 {
429 int src_channel;
430 for (src_channel = 0; src_channel < src_nchannels; ++src_channel) {
431 snd_assert(src_channels[src_channel].area.first % 8 == 0 ||
432 src_channels[src_channel].area.step % 8 == 0,
433 return -ENXIO);
434 }
435 for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
436 snd_assert(dst_channels[dst_channel].area.first % 8 == 0 ||
437 dst_channels[dst_channel].area.step % 8 == 0,
438 return -ENXIO);
439 }
440 }
441#endif
442
443 ttp = data->ttable;
444 dvp = dst_channels;
445 for (dst_channel = 0; dst_channel < dst_nchannels; ++dst_channel) {
446 ttp->func(plugin, src_channels, dvp, ttp, frames);
447 dvp++;
448 ttp++;
449 }
450 return frames;
451}
452
453int getput_index(int format)
454{
455 int sign, width, endian;
456 sign = !snd_pcm_format_signed(format);
457 width = snd_pcm_format_width(format) / 8 - 1;
458 if (width < 0 || width > 3) {
459 snd_printk(KERN_ERR "snd-pcm-oss: invalid format %d\n", format);
460 width = 0;
461 }
462#ifdef SNDRV_LITTLE_ENDIAN
463 endian = snd_pcm_format_big_endian(format);
464#else
465 endian = snd_pcm_format_little_endian(format);
466#endif
467 if (endian < 0)
468 endian = 0;
469 return width * 4 + endian * 2 + sign;
470}
471
472int snd_pcm_plugin_build_route(snd_pcm_plug_t *plug,
473 snd_pcm_plugin_format_t *src_format,
474 snd_pcm_plugin_format_t *dst_format,
475 route_ttable_entry_t *ttable,
476 snd_pcm_plugin_t **r_plugin)
477{
478 route_t *data;
479 snd_pcm_plugin_t *plugin;
480 int err;
481
482 snd_assert(r_plugin != NULL, return -ENXIO);
483 *r_plugin = NULL;
484 snd_assert(src_format->rate == dst_format->rate, return -ENXIO);
485 snd_assert(snd_pcm_format_linear(src_format->format) != 0 &&
486 snd_pcm_format_linear(dst_format->format) != 0,
487 return -ENXIO);
488
489 err = snd_pcm_plugin_build(plug, "attenuated route conversion",
490 src_format, dst_format,
491 sizeof(route_t) + sizeof(data->ttable[0]) * dst_format->channels,
492 &plugin);
493 if (err < 0)
494 return err;
495
496 data = (route_t *) plugin->extra_data;
497
498 data->get = getput_index(src_format->format);
499 snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
500 data->put = getput_index(dst_format->format);
501 snd_assert(data->get >= 0 && data->get < 4*2*2, return -EINVAL);
502 data->conv = conv_index(src_format->format, dst_format->format);
503
504 if (snd_pcm_format_width(src_format->format) == 32)
505 data->sum_type = R_UINT64;
506 else
507 data->sum_type = R_UINT32;
508 data->src_sample_size = snd_pcm_format_width(src_format->format) / 8;
509
510 if ((err = route_load_ttable(plugin, ttable)) < 0) {
511 snd_pcm_plugin_free(plugin);
512 return err;
513 }
514 plugin->transfer = route_transfer;
515 plugin->src_channels_mask = route_src_channels_mask;
516 plugin->dst_channels_mask = route_dst_channels_mask;
517 *r_plugin = plugin;
518 return 0;
519}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
new file mode 100644
index 000000000000..8d94325529a8
--- /dev/null
+++ b/sound/core/pcm.c
@@ -0,0 +1,1074 @@
1/*
2 * Digital Audio (PCM) abstract layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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 <sound/core.h>
27#include <sound/minors.h>
28#include <sound/pcm.h>
29#include <sound/control.h>
30#include <sound/info.h>
31
32MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Abramo Bagnara <abramo@alsa-project.org>");
33MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
34MODULE_LICENSE("GPL");
35
36snd_pcm_t *snd_pcm_devices[SNDRV_CARDS * SNDRV_PCM_DEVICES];
37static LIST_HEAD(snd_pcm_notify_list);
38static DECLARE_MUTEX(register_mutex);
39
40static int snd_pcm_free(snd_pcm_t *pcm);
41static int snd_pcm_dev_free(snd_device_t *device);
42static int snd_pcm_dev_register(snd_device_t *device);
43static int snd_pcm_dev_disconnect(snd_device_t *device);
44static int snd_pcm_dev_unregister(snd_device_t *device);
45
46static int snd_pcm_control_ioctl(snd_card_t * card,
47 snd_ctl_file_t * control,
48 unsigned int cmd, unsigned long arg)
49{
50 unsigned int tmp;
51
52 tmp = card->number * SNDRV_PCM_DEVICES;
53 switch (cmd) {
54 case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
55 {
56 int device;
57
58 if (get_user(device, (int __user *)arg))
59 return -EFAULT;
60 device = device < 0 ? 0 : device + 1;
61 while (device < SNDRV_PCM_DEVICES) {
62 if (snd_pcm_devices[tmp + device])
63 break;
64 device++;
65 }
66 if (device == SNDRV_PCM_DEVICES)
67 device = -1;
68 if (put_user(device, (int __user *)arg))
69 return -EFAULT;
70 return 0;
71 }
72 case SNDRV_CTL_IOCTL_PCM_INFO:
73 {
74 snd_pcm_info_t __user *info;
75 unsigned int device, subdevice;
76 snd_pcm_stream_t stream;
77 snd_pcm_t *pcm;
78 snd_pcm_str_t *pstr;
79 snd_pcm_substream_t *substream;
80 info = (snd_pcm_info_t __user *)arg;
81 if (get_user(device, &info->device))
82 return -EFAULT;
83 if (device >= SNDRV_PCM_DEVICES)
84 return -ENXIO;
85 pcm = snd_pcm_devices[tmp + device];
86 if (pcm == NULL)
87 return -ENXIO;
88 if (get_user(stream, &info->stream))
89 return -EFAULT;
90 if (stream < 0 || stream > 1)
91 return -EINVAL;
92 pstr = &pcm->streams[stream];
93 if (pstr->substream_count == 0)
94 return -ENOENT;
95 if (get_user(subdevice, &info->subdevice))
96 return -EFAULT;
97 if (subdevice >= pstr->substream_count)
98 return -ENXIO;
99 for (substream = pstr->substream; substream; substream = substream->next)
100 if (substream->number == (int)subdevice)
101 break;
102 if (substream == NULL)
103 return -ENXIO;
104 return snd_pcm_info_user(substream, info);
105 }
106 case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
107 {
108 int val;
109
110 if (get_user(val, (int __user *)arg))
111 return -EFAULT;
112 control->prefer_pcm_subdevice = val;
113 return 0;
114 }
115 }
116 return -ENOIOCTLCMD;
117}
118#define STATE(v) [SNDRV_PCM_STATE_##v] = #v
119#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
120#define READY(v) [SNDRV_PCM_READY_##v] = #v
121#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
122#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
123#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
124#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
125#define START(v) [SNDRV_PCM_START_##v] = #v
126#define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
127#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
128
129static char *snd_pcm_stream_names[] = {
130 STREAM(PLAYBACK),
131 STREAM(CAPTURE),
132};
133
134static char *snd_pcm_state_names[] = {
135 STATE(OPEN),
136 STATE(SETUP),
137 STATE(PREPARED),
138 STATE(RUNNING),
139 STATE(XRUN),
140 STATE(DRAINING),
141 STATE(PAUSED),
142 STATE(SUSPENDED),
143};
144
145static char *snd_pcm_access_names[] = {
146 ACCESS(MMAP_INTERLEAVED),
147 ACCESS(MMAP_NONINTERLEAVED),
148 ACCESS(MMAP_COMPLEX),
149 ACCESS(RW_INTERLEAVED),
150 ACCESS(RW_NONINTERLEAVED),
151};
152
153static char *snd_pcm_format_names[] = {
154 FORMAT(S8),
155 FORMAT(U8),
156 FORMAT(S16_LE),
157 FORMAT(S16_BE),
158 FORMAT(U16_LE),
159 FORMAT(U16_BE),
160 FORMAT(S24_LE),
161 FORMAT(S24_BE),
162 FORMAT(U24_LE),
163 FORMAT(U24_BE),
164 FORMAT(S32_LE),
165 FORMAT(S32_BE),
166 FORMAT(U32_LE),
167 FORMAT(U32_BE),
168 FORMAT(FLOAT_LE),
169 FORMAT(FLOAT_BE),
170 FORMAT(FLOAT64_LE),
171 FORMAT(FLOAT64_BE),
172 FORMAT(IEC958_SUBFRAME_LE),
173 FORMAT(IEC958_SUBFRAME_BE),
174 FORMAT(MU_LAW),
175 FORMAT(A_LAW),
176 FORMAT(IMA_ADPCM),
177 FORMAT(MPEG),
178 FORMAT(GSM),
179 FORMAT(SPECIAL),
180 FORMAT(S24_3LE),
181 FORMAT(S24_3BE),
182 FORMAT(U24_3LE),
183 FORMAT(U24_3BE),
184 FORMAT(S20_3LE),
185 FORMAT(S20_3BE),
186 FORMAT(U20_3LE),
187 FORMAT(U20_3BE),
188 FORMAT(S18_3LE),
189 FORMAT(S18_3BE),
190 FORMAT(U18_3LE),
191 FORMAT(U18_3BE),
192};
193
194static char *snd_pcm_subformat_names[] = {
195 SUBFORMAT(STD),
196};
197
198static char *snd_pcm_tstamp_mode_names[] = {
199 TSTAMP(NONE),
200 TSTAMP(MMAP),
201};
202
203static const char *snd_pcm_stream_name(snd_pcm_stream_t stream)
204{
205 snd_assert(stream <= SNDRV_PCM_STREAM_LAST, return NULL);
206 return snd_pcm_stream_names[stream];
207}
208
209static const char *snd_pcm_access_name(snd_pcm_access_t access)
210{
211 snd_assert(access <= SNDRV_PCM_ACCESS_LAST, return NULL);
212 return snd_pcm_access_names[access];
213}
214
215const char *snd_pcm_format_name(snd_pcm_format_t format)
216{
217 snd_assert(format <= SNDRV_PCM_FORMAT_LAST, return NULL);
218 return snd_pcm_format_names[format];
219}
220
221static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
222{
223 snd_assert(subformat <= SNDRV_PCM_SUBFORMAT_LAST, return NULL);
224 return snd_pcm_subformat_names[subformat];
225}
226
227static const char *snd_pcm_tstamp_mode_name(snd_pcm_tstamp_t mode)
228{
229 snd_assert(mode <= SNDRV_PCM_TSTAMP_LAST, return NULL);
230 return snd_pcm_tstamp_mode_names[mode];
231}
232
233static const char *snd_pcm_state_name(snd_pcm_state_t state)
234{
235 snd_assert(state <= SNDRV_PCM_STATE_LAST, return NULL);
236 return snd_pcm_state_names[state];
237}
238
239#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
240#include <linux/soundcard.h>
241static const char *snd_pcm_oss_format_name(int format)
242{
243 switch (format) {
244 case AFMT_MU_LAW:
245 return "MU_LAW";
246 case AFMT_A_LAW:
247 return "A_LAW";
248 case AFMT_IMA_ADPCM:
249 return "IMA_ADPCM";
250 case AFMT_U8:
251 return "U8";
252 case AFMT_S16_LE:
253 return "S16_LE";
254 case AFMT_S16_BE:
255 return "S16_BE";
256 case AFMT_S8:
257 return "S8";
258 case AFMT_U16_LE:
259 return "U16_LE";
260 case AFMT_U16_BE:
261 return "U16_BE";
262 case AFMT_MPEG:
263 return "MPEG";
264 default:
265 return "unknown";
266 }
267}
268#endif
269
270#ifdef CONFIG_PROC_FS
271static void snd_pcm_proc_info_read(snd_pcm_substream_t *substream, snd_info_buffer_t *buffer)
272{
273 snd_pcm_info_t *info;
274 int err;
275
276 snd_runtime_check(substream, return);
277
278 info = kmalloc(sizeof(*info), GFP_KERNEL);
279 if (! info) {
280 printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc\n");
281 return;
282 }
283
284 err = snd_pcm_info(substream, info);
285 if (err < 0) {
286 snd_iprintf(buffer, "error %d\n", err);
287 kfree(info);
288 return;
289 }
290 snd_iprintf(buffer, "card: %d\n", info->card);
291 snd_iprintf(buffer, "device: %d\n", info->device);
292 snd_iprintf(buffer, "subdevice: %d\n", info->subdevice);
293 snd_iprintf(buffer, "stream: %s\n", snd_pcm_stream_name(info->stream));
294 snd_iprintf(buffer, "id: %s\n", info->id);
295 snd_iprintf(buffer, "name: %s\n", info->name);
296 snd_iprintf(buffer, "subname: %s\n", info->subname);
297 snd_iprintf(buffer, "class: %d\n", info->dev_class);
298 snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
299 snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
300 snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
301 kfree(info);
302}
303
304static void snd_pcm_stream_proc_info_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
305{
306 snd_pcm_proc_info_read(((snd_pcm_str_t *)entry->private_data)->substream, buffer);
307}
308
309static void snd_pcm_substream_proc_info_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
310{
311 snd_pcm_proc_info_read((snd_pcm_substream_t *)entry->private_data, buffer);
312}
313
314static void snd_pcm_substream_proc_hw_params_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
315{
316 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
317 snd_pcm_runtime_t *runtime = substream->runtime;
318 if (!runtime) {
319 snd_iprintf(buffer, "closed\n");
320 return;
321 }
322 snd_pcm_stream_lock_irq(substream);
323 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
324 snd_iprintf(buffer, "no setup\n");
325 snd_pcm_stream_unlock_irq(substream);
326 return;
327 }
328 snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
329 snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
330 snd_iprintf(buffer, "subformat: %s\n", snd_pcm_subformat_name(runtime->subformat));
331 snd_iprintf(buffer, "channels: %u\n", runtime->channels);
332 snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den);
333 snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);
334 snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);
335 snd_iprintf(buffer, "tick_time: %u\n", runtime->tick_time);
336#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
337 if (substream->oss.oss) {
338 snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
339 snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);
340 snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate);
341 snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);
342 snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods);
343 snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
344 }
345#endif
346 snd_pcm_stream_unlock_irq(substream);
347}
348
349static void snd_pcm_substream_proc_sw_params_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
350{
351 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
352 snd_pcm_runtime_t *runtime = substream->runtime;
353 if (!runtime) {
354 snd_iprintf(buffer, "closed\n");
355 return;
356 }
357 snd_pcm_stream_lock_irq(substream);
358 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
359 snd_iprintf(buffer, "no setup\n");
360 snd_pcm_stream_unlock_irq(substream);
361 return;
362 }
363 snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
364 snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
365 snd_iprintf(buffer, "sleep_min: %u\n", runtime->sleep_min);
366 snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min);
367 snd_iprintf(buffer, "xfer_align: %lu\n", runtime->xfer_align);
368 snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold);
369 snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold);
370 snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
371 snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
372 snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
373 snd_pcm_stream_unlock_irq(substream);
374}
375
376static void snd_pcm_substream_proc_status_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
377{
378 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
379 snd_pcm_runtime_t *runtime = substream->runtime;
380 snd_pcm_status_t status;
381 int err;
382 if (!runtime) {
383 snd_iprintf(buffer, "closed\n");
384 return;
385 }
386 memset(&status, 0, sizeof(status));
387 err = snd_pcm_status(substream, &status);
388 if (err < 0) {
389 snd_iprintf(buffer, "error %d\n", err);
390 return;
391 }
392 snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
393 snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
394 status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
395 snd_iprintf(buffer, "tstamp : %ld.%09ld\n",
396 status.tstamp.tv_sec, status.tstamp.tv_nsec);
397 snd_iprintf(buffer, "delay : %ld\n", status.delay);
398 snd_iprintf(buffer, "avail : %ld\n", status.avail);
399 snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max);
400 snd_iprintf(buffer, "-----\n");
401 snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
402 snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
403}
404#endif
405
406#ifdef CONFIG_SND_DEBUG
407static void snd_pcm_xrun_debug_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
408{
409 snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
410 snd_iprintf(buffer, "%d\n", pstr->xrun_debug);
411}
412
413static void snd_pcm_xrun_debug_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer)
414{
415 snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
416 char line[64];
417 if (!snd_info_get_line(buffer, line, sizeof(line)))
418 pstr->xrun_debug = simple_strtoul(line, NULL, 10);
419}
420#endif
421
422static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr)
423{
424 snd_pcm_t *pcm = pstr->pcm;
425 snd_info_entry_t *entry;
426 char name[16];
427
428 sprintf(name, "pcm%i%c", pcm->device,
429 pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
430 if ((entry = snd_info_create_card_entry(pcm->card, name, pcm->card->proc_root)) == NULL)
431 return -ENOMEM;
432 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
433 if (snd_info_register(entry) < 0) {
434 snd_info_free_entry(entry);
435 return -ENOMEM;
436 }
437 pstr->proc_root = entry;
438
439 if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
440 snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read);
441 if (snd_info_register(entry) < 0) {
442 snd_info_free_entry(entry);
443 entry = NULL;
444 }
445 }
446 pstr->proc_info_entry = entry;
447
448#ifdef CONFIG_SND_DEBUG
449 if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", pstr->proc_root)) != NULL) {
450 entry->c.text.read_size = 64;
451 entry->c.text.read = snd_pcm_xrun_debug_read;
452 entry->c.text.write_size = 64;
453 entry->c.text.write = snd_pcm_xrun_debug_write;
454 entry->private_data = pstr;
455 if (snd_info_register(entry) < 0) {
456 snd_info_free_entry(entry);
457 entry = NULL;
458 }
459 }
460 pstr->proc_xrun_debug_entry = entry;
461#endif
462 return 0;
463}
464
465static int snd_pcm_stream_proc_done(snd_pcm_str_t *pstr)
466{
467#ifdef CONFIG_SND_DEBUG
468 if (pstr->proc_xrun_debug_entry) {
469 snd_info_unregister(pstr->proc_xrun_debug_entry);
470 pstr->proc_xrun_debug_entry = NULL;
471 }
472#endif
473 if (pstr->proc_info_entry) {
474 snd_info_unregister(pstr->proc_info_entry);
475 pstr->proc_info_entry = NULL;
476 }
477 if (pstr->proc_root) {
478 snd_info_unregister(pstr->proc_root);
479 pstr->proc_root = NULL;
480 }
481 return 0;
482}
483
484static int snd_pcm_substream_proc_init(snd_pcm_substream_t *substream)
485{
486 snd_info_entry_t *entry;
487 snd_card_t *card;
488 char name[16];
489
490 card = substream->pcm->card;
491
492 sprintf(name, "sub%i", substream->number);
493 if ((entry = snd_info_create_card_entry(card, name, substream->pstr->proc_root)) == NULL)
494 return -ENOMEM;
495 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
496 if (snd_info_register(entry) < 0) {
497 snd_info_free_entry(entry);
498 return -ENOMEM;
499 }
500 substream->proc_root = entry;
501
502 if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
503 snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read);
504 if (snd_info_register(entry) < 0) {
505 snd_info_free_entry(entry);
506 entry = NULL;
507 }
508 }
509 substream->proc_info_entry = entry;
510
511 if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
512 snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read);
513 if (snd_info_register(entry) < 0) {
514 snd_info_free_entry(entry);
515 entry = NULL;
516 }
517 }
518 substream->proc_hw_params_entry = entry;
519
520 if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
521 snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read);
522 if (snd_info_register(entry) < 0) {
523 snd_info_free_entry(entry);
524 entry = NULL;
525 }
526 }
527 substream->proc_sw_params_entry = entry;
528
529 if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
530 snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read);
531 if (snd_info_register(entry) < 0) {
532 snd_info_free_entry(entry);
533 entry = NULL;
534 }
535 }
536 substream->proc_status_entry = entry;
537
538 return 0;
539}
540
541static int snd_pcm_substream_proc_done(snd_pcm_substream_t *substream)
542{
543 if (substream->proc_info_entry) {
544 snd_info_unregister(substream->proc_info_entry);
545 substream->proc_info_entry = NULL;
546 }
547 if (substream->proc_hw_params_entry) {
548 snd_info_unregister(substream->proc_hw_params_entry);
549 substream->proc_hw_params_entry = NULL;
550 }
551 if (substream->proc_sw_params_entry) {
552 snd_info_unregister(substream->proc_sw_params_entry);
553 substream->proc_sw_params_entry = NULL;
554 }
555 if (substream->proc_status_entry) {
556 snd_info_unregister(substream->proc_status_entry);
557 substream->proc_status_entry = NULL;
558 }
559 if (substream->proc_root) {
560 snd_info_unregister(substream->proc_root);
561 substream->proc_root = NULL;
562 }
563 return 0;
564}
565
566/**
567 * snd_pcm_new_stream - create a new PCM stream
568 * @pcm: the pcm instance
569 * @stream: the stream direction, SNDRV_PCM_STREAM_XXX
570 * @substream_count: the number of substreams
571 *
572 * Creates a new stream for the pcm.
573 * The corresponding stream on the pcm must have been empty before
574 * calling this, i.e. zero must be given to the argument of
575 * snd_pcm_new().
576 *
577 * Returns zero if successful, or a negative error code on failure.
578 */
579int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count)
580{
581 int idx, err;
582 snd_pcm_str_t *pstr = &pcm->streams[stream];
583 snd_pcm_substream_t *substream, *prev;
584
585#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
586 init_MUTEX(&pstr->oss.setup_mutex);
587#endif
588 pstr->stream = stream;
589 pstr->pcm = pcm;
590 pstr->substream_count = substream_count;
591 pstr->reg = &snd_pcm_reg[stream];
592 if (substream_count > 0) {
593 err = snd_pcm_stream_proc_init(pstr);
594 if (err < 0)
595 return err;
596 }
597 prev = NULL;
598 for (idx = 0, prev = NULL; idx < substream_count; idx++) {
599 substream = kcalloc(1, sizeof(*substream), GFP_KERNEL);
600 if (substream == NULL)
601 return -ENOMEM;
602 substream->pcm = pcm;
603 substream->pstr = pstr;
604 substream->number = idx;
605 substream->stream = stream;
606 sprintf(substream->name, "subdevice #%i", idx);
607 substream->buffer_bytes_max = UINT_MAX;
608 if (prev == NULL)
609 pstr->substream = substream;
610 else
611 prev->next = substream;
612 err = snd_pcm_substream_proc_init(substream);
613 if (err < 0) {
614 kfree(substream);
615 return err;
616 }
617 substream->group = &substream->self_group;
618 spin_lock_init(&substream->self_group.lock);
619 INIT_LIST_HEAD(&substream->self_group.substreams);
620 list_add_tail(&substream->link_list, &substream->self_group.substreams);
621 spin_lock_init(&substream->timer_lock);
622 prev = substream;
623 }
624 return 0;
625}
626
627/**
628 * snd_pcm_new - create a new PCM instance
629 * @card: the card instance
630 * @id: the id string
631 * @device: the device index (zero based)
632 * @playback_count: the number of substreams for playback
633 * @capture_count: the number of substreams for capture
634 * @rpcm: the pointer to store the new pcm instance
635 *
636 * Creates a new PCM instance.
637 *
638 * The pcm operators have to be set afterwards to the new instance
639 * via snd_pcm_set_ops().
640 *
641 * Returns zero if successful, or a negative error code on failure.
642 */
643int snd_pcm_new(snd_card_t * card, char *id, int device,
644 int playback_count, int capture_count,
645 snd_pcm_t ** rpcm)
646{
647 snd_pcm_t *pcm;
648 int err;
649 static snd_device_ops_t ops = {
650 .dev_free = snd_pcm_dev_free,
651 .dev_register = snd_pcm_dev_register,
652 .dev_disconnect = snd_pcm_dev_disconnect,
653 .dev_unregister = snd_pcm_dev_unregister
654 };
655
656 snd_assert(rpcm != NULL, return -EINVAL);
657 *rpcm = NULL;
658 snd_assert(card != NULL, return -ENXIO);
659 pcm = kcalloc(1, sizeof(*pcm), GFP_KERNEL);
660 if (pcm == NULL)
661 return -ENOMEM;
662 pcm->card = card;
663 pcm->device = device;
664 if (id) {
665 strlcpy(pcm->id, id, sizeof(pcm->id));
666 }
667 if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
668 snd_pcm_free(pcm);
669 return err;
670 }
671 if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) {
672 snd_pcm_free(pcm);
673 return err;
674 }
675 init_MUTEX(&pcm->open_mutex);
676 init_waitqueue_head(&pcm->open_wait);
677 if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
678 snd_pcm_free(pcm);
679 return err;
680 }
681 *rpcm = pcm;
682 return 0;
683}
684
685static void snd_pcm_free_stream(snd_pcm_str_t * pstr)
686{
687 snd_pcm_substream_t *substream, *substream_next;
688#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
689 snd_pcm_oss_setup_t *setup, *setupn;
690#endif
691 substream = pstr->substream;
692 while (substream) {
693 substream_next = substream->next;
694 snd_pcm_substream_proc_done(substream);
695 kfree(substream);
696 substream = substream_next;
697 }
698 snd_pcm_stream_proc_done(pstr);
699#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
700 for (setup = pstr->oss.setup_list; setup; setup = setupn) {
701 setupn = setup->next;
702 kfree(setup->task_name);
703 kfree(setup);
704 }
705#endif
706}
707
708static int snd_pcm_free(snd_pcm_t *pcm)
709{
710 snd_assert(pcm != NULL, return -ENXIO);
711 if (pcm->private_free)
712 pcm->private_free(pcm);
713 snd_pcm_lib_preallocate_free_for_all(pcm);
714 snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]);
715 snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]);
716 kfree(pcm);
717 return 0;
718}
719
720static int snd_pcm_dev_free(snd_device_t *device)
721{
722 snd_pcm_t *pcm = device->device_data;
723 return snd_pcm_free(pcm);
724}
725
726static void snd_pcm_tick_timer_func(unsigned long data)
727{
728 snd_pcm_substream_t *substream = (snd_pcm_substream_t*) data;
729 snd_pcm_tick_elapsed(substream);
730}
731
732int snd_pcm_open_substream(snd_pcm_t *pcm, int stream,
733 snd_pcm_substream_t **rsubstream)
734{
735 snd_pcm_str_t * pstr;
736 snd_pcm_substream_t * substream;
737 snd_pcm_runtime_t * runtime;
738 snd_ctl_file_t *kctl;
739 snd_card_t *card;
740 struct list_head *list;
741 int prefer_subdevice = -1;
742 size_t size;
743
744 snd_assert(rsubstream != NULL, return -EINVAL);
745 *rsubstream = NULL;
746 snd_assert(pcm != NULL, return -ENXIO);
747 pstr = &pcm->streams[stream];
748 if (pstr->substream == NULL)
749 return -ENODEV;
750
751 card = pcm->card;
752 down_read(&card->controls_rwsem);
753 list_for_each(list, &card->ctl_files) {
754 kctl = snd_ctl_file(list);
755 if (kctl->pid == current->pid) {
756 prefer_subdevice = kctl->prefer_pcm_subdevice;
757 break;
758 }
759 }
760 up_read(&card->controls_rwsem);
761
762 if (pstr->substream_count == 0)
763 return -ENODEV;
764 switch (stream) {
765 case SNDRV_PCM_STREAM_PLAYBACK:
766 if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
767 for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
768 if (SUBSTREAM_BUSY(substream))
769 return -EAGAIN;
770 }
771 }
772 break;
773 case SNDRV_PCM_STREAM_CAPTURE:
774 if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
775 for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
776 if (SUBSTREAM_BUSY(substream))
777 return -EAGAIN;
778 }
779 }
780 break;
781 default:
782 return -EINVAL;
783 }
784
785 if (prefer_subdevice >= 0) {
786 for (substream = pstr->substream; substream; substream = substream->next)
787 if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
788 goto __ok;
789 }
790 for (substream = pstr->substream; substream; substream = substream->next)
791 if (!SUBSTREAM_BUSY(substream))
792 break;
793 __ok:
794 if (substream == NULL)
795 return -EAGAIN;
796
797 runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL);
798 if (runtime == NULL)
799 return -ENOMEM;
800
801 size = PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t));
802 runtime->status = snd_malloc_pages(size, GFP_KERNEL);
803 if (runtime->status == NULL) {
804 kfree(runtime);
805 return -ENOMEM;
806 }
807 memset((void*)runtime->status, 0, size);
808
809 size = PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t));
810 runtime->control = snd_malloc_pages(size, GFP_KERNEL);
811 if (runtime->control == NULL) {
812 snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)));
813 kfree(runtime);
814 return -ENOMEM;
815 }
816 memset((void*)runtime->control, 0, size);
817
818 init_waitqueue_head(&runtime->sleep);
819 atomic_set(&runtime->mmap_count, 0);
820 init_timer(&runtime->tick_timer);
821 runtime->tick_timer.function = snd_pcm_tick_timer_func;
822 runtime->tick_timer.data = (unsigned long) substream;
823
824 runtime->status->state = SNDRV_PCM_STATE_OPEN;
825
826 substream->runtime = runtime;
827 substream->private_data = pcm->private_data;
828 pstr->substream_opened++;
829 *rsubstream = substream;
830 return 0;
831}
832
833void snd_pcm_release_substream(snd_pcm_substream_t *substream)
834{
835 snd_pcm_runtime_t * runtime;
836 substream->file = NULL;
837 runtime = substream->runtime;
838 snd_assert(runtime != NULL, return);
839 if (runtime->private_free != NULL)
840 runtime->private_free(runtime);
841 snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)));
842 snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)));
843 kfree(runtime->hw_constraints.rules);
844 kfree(runtime);
845 substream->runtime = NULL;
846 substream->pstr->substream_opened--;
847}
848
849static int snd_pcm_dev_register(snd_device_t *device)
850{
851 int idx, cidx, err;
852 unsigned short minor;
853 snd_pcm_substream_t *substream;
854 struct list_head *list;
855 char str[16];
856 snd_pcm_t *pcm = device->device_data;
857
858 snd_assert(pcm != NULL && device != NULL, return -ENXIO);
859 down(&register_mutex);
860 idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
861 if (snd_pcm_devices[idx]) {
862 up(&register_mutex);
863 return -EBUSY;
864 }
865 snd_pcm_devices[idx] = pcm;
866 for (cidx = 0; cidx < 2; cidx++) {
867 int devtype = -1;
868 if (pcm->streams[cidx].substream == NULL)
869 continue;
870 switch (cidx) {
871 case SNDRV_PCM_STREAM_PLAYBACK:
872 sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
873 minor = SNDRV_MINOR_PCM_PLAYBACK + idx;
874 devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
875 break;
876 case SNDRV_PCM_STREAM_CAPTURE:
877 sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
878 minor = SNDRV_MINOR_PCM_CAPTURE + idx;
879 devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
880 break;
881 }
882 if ((err = snd_register_device(devtype, pcm->card, pcm->device, pcm->streams[cidx].reg, str)) < 0) {
883 snd_pcm_devices[idx] = NULL;
884 up(&register_mutex);
885 return err;
886 }
887 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
888 snd_pcm_timer_init(substream);
889 }
890 list_for_each(list, &snd_pcm_notify_list) {
891 snd_pcm_notify_t *notify;
892 notify = list_entry(list, snd_pcm_notify_t, list);
893 notify->n_register(pcm);
894 }
895 up(&register_mutex);
896 return 0;
897}
898
899static int snd_pcm_dev_disconnect(snd_device_t *device)
900{
901 snd_pcm_t *pcm = device->device_data;
902 struct list_head *list;
903 snd_pcm_substream_t *substream;
904 int idx, cidx;
905
906 down(&register_mutex);
907 idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
908 snd_pcm_devices[idx] = NULL;
909 for (cidx = 0; cidx < 2; cidx++)
910 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
911 if (substream->runtime)
912 substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
913 list_for_each(list, &snd_pcm_notify_list) {
914 snd_pcm_notify_t *notify;
915 notify = list_entry(list, snd_pcm_notify_t, list);
916 notify->n_disconnect(pcm);
917 }
918 up(&register_mutex);
919 return 0;
920}
921
922static int snd_pcm_dev_unregister(snd_device_t *device)
923{
924 int idx, cidx, devtype;
925 snd_pcm_substream_t *substream;
926 struct list_head *list;
927 snd_pcm_t *pcm = device->device_data;
928
929 snd_assert(pcm != NULL, return -ENXIO);
930 down(&register_mutex);
931 idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device;
932 snd_pcm_devices[idx] = NULL;
933 for (cidx = 0; cidx < 2; cidx++) {
934 devtype = -1;
935 switch (cidx) {
936 case SNDRV_PCM_STREAM_PLAYBACK:
937 devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
938 break;
939 case SNDRV_PCM_STREAM_CAPTURE:
940 devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
941 break;
942 }
943 snd_unregister_device(devtype, pcm->card, pcm->device);
944 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
945 snd_pcm_timer_done(substream);
946 }
947 list_for_each(list, &snd_pcm_notify_list) {
948 snd_pcm_notify_t *notify;
949 notify = list_entry(list, snd_pcm_notify_t, list);
950 notify->n_unregister(pcm);
951 }
952 up(&register_mutex);
953 return snd_pcm_free(pcm);
954}
955
956int snd_pcm_notify(snd_pcm_notify_t *notify, int nfree)
957{
958 int idx;
959
960 snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL);
961 down(&register_mutex);
962 if (nfree) {
963 list_del(&notify->list);
964 for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
965 if (snd_pcm_devices[idx] == NULL)
966 continue;
967 notify->n_unregister(snd_pcm_devices[idx]);
968 }
969 } else {
970 list_add_tail(&notify->list, &snd_pcm_notify_list);
971 for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
972 if (snd_pcm_devices[idx] == NULL)
973 continue;
974 notify->n_register(snd_pcm_devices[idx]);
975 }
976 }
977 up(&register_mutex);
978 return 0;
979}
980
981/*
982 * Info interface
983 */
984
985static void snd_pcm_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
986{
987 int idx;
988 snd_pcm_t *pcm;
989
990 down(&register_mutex);
991 for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) {
992 pcm = snd_pcm_devices[idx];
993 if (pcm == NULL)
994 continue;
995 snd_iprintf(buffer, "%02i-%02i: %s : %s", idx / SNDRV_PCM_DEVICES,
996 idx % SNDRV_PCM_DEVICES, pcm->id, pcm->name);
997 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
998 snd_iprintf(buffer, " : playback %i", pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
999 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
1000 snd_iprintf(buffer, " : capture %i", pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
1001 snd_iprintf(buffer, "\n");
1002 }
1003 up(&register_mutex);
1004}
1005
1006/*
1007 * ENTRY functions
1008 */
1009
1010static snd_info_entry_t *snd_pcm_proc_entry = NULL;
1011
1012static int __init alsa_pcm_init(void)
1013{
1014 snd_info_entry_t *entry;
1015
1016 snd_ctl_register_ioctl(snd_pcm_control_ioctl);
1017 snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
1018 if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
1019 snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read);
1020 if (snd_info_register(entry) < 0) {
1021 snd_info_free_entry(entry);
1022 entry = NULL;
1023 }
1024 }
1025 snd_pcm_proc_entry = entry;
1026 return 0;
1027}
1028
1029static void __exit alsa_pcm_exit(void)
1030{
1031 snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
1032 snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
1033 if (snd_pcm_proc_entry) {
1034 snd_info_unregister(snd_pcm_proc_entry);
1035 snd_pcm_proc_entry = NULL;
1036 }
1037}
1038
1039module_init(alsa_pcm_init)
1040module_exit(alsa_pcm_exit)
1041
1042EXPORT_SYMBOL(snd_pcm_devices);
1043EXPORT_SYMBOL(snd_pcm_new);
1044EXPORT_SYMBOL(snd_pcm_new_stream);
1045EXPORT_SYMBOL(snd_pcm_notify);
1046EXPORT_SYMBOL(snd_pcm_open_substream);
1047EXPORT_SYMBOL(snd_pcm_release_substream);
1048EXPORT_SYMBOL(snd_pcm_format_name);
1049 /* pcm_native.c */
1050EXPORT_SYMBOL(snd_pcm_link_rwlock);
1051EXPORT_SYMBOL(snd_pcm_start);
1052#ifdef CONFIG_PM
1053EXPORT_SYMBOL(snd_pcm_suspend);
1054EXPORT_SYMBOL(snd_pcm_suspend_all);
1055#endif
1056EXPORT_SYMBOL(snd_pcm_kernel_playback_ioctl);
1057EXPORT_SYMBOL(snd_pcm_kernel_capture_ioctl);
1058EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
1059EXPORT_SYMBOL(snd_pcm_mmap_data);
1060#if SNDRV_PCM_INFO_MMAP_IOMEM
1061EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
1062#endif
1063 /* pcm_misc.c */
1064EXPORT_SYMBOL(snd_pcm_format_signed);
1065EXPORT_SYMBOL(snd_pcm_format_unsigned);
1066EXPORT_SYMBOL(snd_pcm_format_linear);
1067EXPORT_SYMBOL(snd_pcm_format_little_endian);
1068EXPORT_SYMBOL(snd_pcm_format_big_endian);
1069EXPORT_SYMBOL(snd_pcm_format_width);
1070EXPORT_SYMBOL(snd_pcm_format_physical_width);
1071EXPORT_SYMBOL(snd_pcm_format_silence_64);
1072EXPORT_SYMBOL(snd_pcm_format_set_silence);
1073EXPORT_SYMBOL(snd_pcm_build_linear_format);
1074EXPORT_SYMBOL(snd_pcm_limit_hw_rates);
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c
new file mode 100644
index 000000000000..3920bf0eebbf
--- /dev/null
+++ b/sound/core/pcm_compat.c
@@ -0,0 +1,513 @@
1/*
2 * 32bit -> 64bit ioctl wrapper for PCM API
3 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21/* This file included from pcm_native.c */
22
23#include <linux/compat.h>
24
25static int snd_pcm_ioctl_delay_compat(snd_pcm_substream_t *substream,
26 s32 __user *src)
27{
28 snd_pcm_sframes_t delay;
29 mm_segment_t fs;
30 int err;
31
32 fs = snd_enter_user();
33 err = snd_pcm_delay(substream, &delay);
34 snd_leave_user(fs);
35 if (err < 0)
36 return err;
37 if (put_user(delay, src))
38 return -EFAULT;
39 return err;
40}
41
42static int snd_pcm_ioctl_rewind_compat(snd_pcm_substream_t *substream,
43 u32 __user *src)
44{
45 snd_pcm_uframes_t frames;
46 int err;
47
48 if (get_user(frames, src))
49 return -EFAULT;
50 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
51 err = snd_pcm_playback_rewind(substream, frames);
52 else
53 err = snd_pcm_capture_rewind(substream, frames);
54 if (put_user(err, src))
55 return -EFAULT;
56 return err < 0 ? err : 0;
57}
58
59static int snd_pcm_ioctl_forward_compat(snd_pcm_substream_t *substream,
60 u32 __user *src)
61{
62 snd_pcm_uframes_t frames;
63 int err;
64
65 if (get_user(frames, src))
66 return -EFAULT;
67 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
68 err = snd_pcm_playback_forward(substream, frames);
69 else
70 err = snd_pcm_capture_forward(substream, frames);
71 if (put_user(err, src))
72 return -EFAULT;
73 return err < 0 ? err : 0;
74}
75
76struct sndrv_pcm_hw_params32 {
77 u32 flags;
78 struct sndrv_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; /* this must be identical */
79 struct sndrv_mask mres[5]; /* reserved masks */
80 struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
81 struct sndrv_interval ires[9]; /* reserved intervals */
82 u32 rmask;
83 u32 cmask;
84 u32 info;
85 u32 msbits;
86 u32 rate_num;
87 u32 rate_den;
88 u32 fifo_size;
89 unsigned char reserved[64];
90};
91
92struct sndrv_pcm_sw_params32 {
93 s32 tstamp_mode;
94 u32 period_step;
95 u32 sleep_min;
96 u32 avail_min;
97 u32 xfer_align;
98 u32 start_threshold;
99 u32 stop_threshold;
100 u32 silence_threshold;
101 u32 silence_size;
102 u32 boundary;
103 unsigned char reserved[64];
104};
105
106static int snd_pcm_ioctl_sw_params_compat(snd_pcm_substream_t *substream,
107 struct sndrv_pcm_sw_params32 __user *src)
108{
109 snd_pcm_sw_params_t params;
110 int err;
111
112 memset(&params, 0, sizeof(params));
113 if (get_user(params.tstamp_mode, &src->tstamp_mode) ||
114 get_user(params.period_step, &src->period_step) ||
115 get_user(params.sleep_min, &src->sleep_min) ||
116 get_user(params.avail_min, &src->avail_min) ||
117 get_user(params.xfer_align, &src->xfer_align) ||
118 get_user(params.start_threshold, &src->start_threshold) ||
119 get_user(params.stop_threshold, &src->stop_threshold) ||
120 get_user(params.silence_threshold, &src->silence_threshold) ||
121 get_user(params.silence_size, &src->silence_size))
122 return -EFAULT;
123 err = snd_pcm_sw_params(substream, &params);
124 if (err < 0)
125 return err;
126 if (put_user(params.boundary, &src->boundary))
127 return -EFAULT;
128 return err;
129}
130
131struct sndrv_pcm_channel_info32 {
132 u32 channel;
133 u32 offset;
134 u32 first;
135 u32 step;
136};
137
138static int snd_pcm_ioctl_channel_info_compat(snd_pcm_substream_t *substream,
139 struct sndrv_pcm_channel_info32 __user *src)
140{
141 snd_pcm_channel_info_t info;
142 int err;
143
144 if (get_user(info.channel, &src->channel) ||
145 get_user(info.offset, &src->offset) ||
146 get_user(info.first, &src->first) ||
147 get_user(info.step, &src->step))
148 return -EFAULT;
149 err = snd_pcm_channel_info(substream, &info);
150 if (err < 0)
151 return err;
152 if (put_user(info.channel, &src->channel) ||
153 put_user(info.offset, &src->offset) ||
154 put_user(info.first, &src->first) ||
155 put_user(info.step, &src->step))
156 return -EFAULT;
157 return err;
158}
159
160struct sndrv_pcm_status32 {
161 s32 state;
162 struct compat_timespec trigger_tstamp;
163 struct compat_timespec tstamp;
164 u32 appl_ptr;
165 u32 hw_ptr;
166 s32 delay;
167 u32 avail;
168 u32 avail_max;
169 u32 overrange;
170 s32 suspended_state;
171 unsigned char reserved[60];
172} __attribute__((packed));
173
174
175static int snd_pcm_status_user_compat(snd_pcm_substream_t *substream,
176 struct sndrv_pcm_status32 __user *src)
177{
178 snd_pcm_status_t status;
179 int err;
180
181 err = snd_pcm_status(substream, &status);
182 if (err < 0)
183 return err;
184
185 if (put_user(status.state, &src->state) ||
186 put_user(status.trigger_tstamp.tv_sec, &src->trigger_tstamp.tv_sec) ||
187 put_user(status.trigger_tstamp.tv_nsec, &src->trigger_tstamp.tv_nsec) ||
188 put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
189 put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
190 put_user(status.appl_ptr, &src->appl_ptr) ||
191 put_user(status.hw_ptr, &src->hw_ptr) ||
192 put_user(status.delay, &src->delay) ||
193 put_user(status.avail, &src->avail) ||
194 put_user(status.avail_max, &src->avail_max) ||
195 put_user(status.overrange, &src->overrange) ||
196 put_user(status.suspended_state, &src->suspended_state))
197 return -EFAULT;
198
199 return err;
200}
201
202/* recalcuate the boundary within 32bit */
203static void recalculate_boundary(snd_pcm_runtime_t *runtime)
204{
205 if (! runtime->buffer_size)
206 return;
207 runtime->boundary = runtime->buffer_size;
208 while (runtime->boundary * 2 <= 0x7fffffffUL - runtime->buffer_size)
209 runtime->boundary *= 2;
210}
211
212/* both for HW_PARAMS and HW_REFINE */
213static int snd_pcm_ioctl_hw_params_compat(snd_pcm_substream_t *substream,
214 int refine,
215 struct sndrv_pcm_hw_params32 __user *data32)
216{
217 struct sndrv_pcm_hw_params *data;
218 snd_pcm_runtime_t *runtime;
219 int err;
220
221 if (! (runtime = substream->runtime))
222 return -ENOTTY;
223
224 data = kmalloc(sizeof(*data), GFP_KERNEL);
225 if (data == NULL)
226 return -ENOMEM;
227 /* only fifo_size is different, so just copy all */
228 if (copy_from_user(data, data32, sizeof(*data32))) {
229 err = -EFAULT;
230 goto error;
231 }
232 if (refine)
233 err = snd_pcm_hw_refine(substream, data);
234 else
235 err = snd_pcm_hw_params(substream, data);
236 if (err < 0)
237 goto error;
238 if (copy_to_user(data32, data, sizeof(*data32)) ||
239 put_user(data->fifo_size, &data32->fifo_size)) {
240 err = -EFAULT;
241 goto error;
242 }
243
244 if (! refine)
245 recalculate_boundary(runtime);
246 error:
247 kfree(data);
248 return err;
249}
250
251
252/*
253 */
254struct sndrv_xferi32 {
255 s32 result;
256 u32 buf;
257 u32 frames;
258};
259
260static int snd_pcm_ioctl_xferi_compat(snd_pcm_substream_t *substream,
261 int dir, struct sndrv_xferi32 __user *data32)
262{
263 compat_caddr_t buf;
264 u32 frames;
265 int err;
266
267 if (! substream->runtime)
268 return -ENOTTY;
269 if (substream->stream != dir)
270 return -EINVAL;
271 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
272 return -EBADFD;
273
274 if (get_user(buf, &data32->buf) ||
275 get_user(frames, &data32->frames))
276 return -EFAULT;
277
278 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
279 err = snd_pcm_lib_write(substream, compat_ptr(buf), frames);
280 else
281 err = snd_pcm_lib_read(substream, compat_ptr(buf), frames);
282 if (err < 0)
283 return err;
284 /* copy the result */
285 if (put_user(err, &data32->result))
286 return -EFAULT;
287 return 0;
288}
289
290
291/* snd_xfern needs remapping of bufs */
292struct sndrv_xfern32 {
293 s32 result;
294 u32 bufs; /* this is void **; */
295 u32 frames;
296};
297
298/*
299 * xfern ioctl nees to copy (up to) 128 pointers on stack.
300 * although we may pass the copied pointers through f_op->ioctl, but the ioctl
301 * handler there expands again the same 128 pointers on stack, so it is better
302 * to handle the function (calling pcm_readv/writev) directly in this handler.
303 */
304static int snd_pcm_ioctl_xfern_compat(snd_pcm_substream_t *substream,
305 int dir, struct sndrv_xfern32 __user *data32)
306{
307 compat_caddr_t buf;
308 compat_caddr_t __user *bufptr;
309 u32 frames;
310 void __user **bufs;
311 int err, ch, i;
312
313 if (! substream->runtime)
314 return -ENOTTY;
315 if (substream->stream != dir)
316 return -EINVAL;
317
318 if ((ch = substream->runtime->channels) > 128)
319 return -EINVAL;
320 if (get_user(buf, &data32->bufs) ||
321 get_user(frames, &data32->frames))
322 return -EFAULT;
323 bufptr = compat_ptr(buf);
324 bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL);
325 if (bufs == NULL)
326 return -ENOMEM;
327 for (i = 0; i < ch; i++) {
328 u32 ptr;
329 if (get_user(ptr, bufptr)) {
330 kfree(bufs);
331 return -EFAULT;
332 }
333 bufs[ch] = compat_ptr(ptr);
334 bufptr++;
335 }
336 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
337 err = snd_pcm_lib_writev(substream, bufs, frames);
338 else
339 err = snd_pcm_lib_readv(substream, bufs, frames);
340 if (err >= 0) {
341 if (put_user(err, &data32->result))
342 err = -EFAULT;
343 }
344 kfree(bufs);
345 return err;
346}
347
348
349struct sndrv_pcm_mmap_status32 {
350 s32 state;
351 s32 pad1;
352 u32 hw_ptr;
353 struct compat_timespec tstamp;
354 s32 suspended_state;
355} __attribute__((packed));
356
357struct sndrv_pcm_mmap_control32 {
358 u32 appl_ptr;
359 u32 avail_min;
360};
361
362struct sndrv_pcm_sync_ptr32 {
363 u32 flags;
364 union {
365 struct sndrv_pcm_mmap_status32 status;
366 unsigned char reserved[64];
367 } s;
368 union {
369 struct sndrv_pcm_mmap_control32 control;
370 unsigned char reserved[64];
371 } c;
372} __attribute__((packed));
373
374static int snd_pcm_ioctl_sync_ptr_compat(snd_pcm_substream_t *substream,
375 struct sndrv_pcm_sync_ptr32 __user *src)
376{
377 snd_pcm_runtime_t *runtime = substream->runtime;
378 volatile struct sndrv_pcm_mmap_status *status;
379 volatile struct sndrv_pcm_mmap_control *control;
380 u32 sflags;
381 struct sndrv_pcm_mmap_control scontrol;
382 struct sndrv_pcm_mmap_status sstatus;
383 int err;
384
385 snd_assert(runtime, return -EINVAL);
386
387 if (get_user(sflags, &src->flags) ||
388 get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
389 get_user(scontrol.avail_min, &src->c.control.avail_min))
390 return -EFAULT;
391 if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
392 err = snd_pcm_hwsync(substream);
393 if (err < 0)
394 return err;
395 }
396 status = runtime->status;
397 control = runtime->control;
398 snd_pcm_stream_lock_irq(substream);
399 if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL))
400 control->appl_ptr = scontrol.appl_ptr;
401 else
402 scontrol.appl_ptr = control->appl_ptr;
403 if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
404 control->avail_min = scontrol.avail_min;
405 else
406 scontrol.avail_min = control->avail_min;
407 sstatus.state = status->state;
408 sstatus.hw_ptr = status->hw_ptr;
409 sstatus.tstamp = status->tstamp;
410 sstatus.suspended_state = status->suspended_state;
411 snd_pcm_stream_unlock_irq(substream);
412 if (put_user(sstatus.state, &src->s.status.state) ||
413 put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) ||
414 put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp.tv_sec) ||
415 put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp.tv_nsec) ||
416 put_user(sstatus.suspended_state, &src->s.status.suspended_state) ||
417 put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) ||
418 put_user(scontrol.avail_min, &src->c.control.avail_min))
419 return -EFAULT;
420
421 return 0;
422}
423
424
425/*
426 */
427enum {
428 SNDRV_PCM_IOCTL_HW_REFINE32 = _IOWR('A', 0x10, struct sndrv_pcm_hw_params32),
429 SNDRV_PCM_IOCTL_HW_PARAMS32 = _IOWR('A', 0x11, struct sndrv_pcm_hw_params32),
430 SNDRV_PCM_IOCTL_SW_PARAMS32 = _IOWR('A', 0x13, struct sndrv_pcm_sw_params32),
431 SNDRV_PCM_IOCTL_STATUS32 = _IOR('A', 0x20, struct sndrv_pcm_status32),
432 SNDRV_PCM_IOCTL_DELAY32 = _IOR('A', 0x21, s32),
433 SNDRV_PCM_IOCTL_CHANNEL_INFO32 = _IOR('A', 0x32, struct sndrv_pcm_channel_info32),
434 SNDRV_PCM_IOCTL_REWIND32 = _IOW('A', 0x46, u32),
435 SNDRV_PCM_IOCTL_FORWARD32 = _IOW('A', 0x49, u32),
436 SNDRV_PCM_IOCTL_WRITEI_FRAMES32 = _IOW('A', 0x50, struct sndrv_xferi32),
437 SNDRV_PCM_IOCTL_READI_FRAMES32 = _IOR('A', 0x51, struct sndrv_xferi32),
438 SNDRV_PCM_IOCTL_WRITEN_FRAMES32 = _IOW('A', 0x52, struct sndrv_xfern32),
439 SNDRV_PCM_IOCTL_READN_FRAMES32 = _IOR('A', 0x53, struct sndrv_xfern32),
440 SNDRV_PCM_IOCTL_SYNC_PTR32 = _IOWR('A', 0x23, struct sndrv_pcm_sync_ptr32),
441
442};
443
444static long snd_pcm_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
445{
446 snd_pcm_file_t *pcm_file;
447 snd_pcm_substream_t *substream;
448 void __user *argp = compat_ptr(arg);
449
450 pcm_file = file->private_data;
451 if (! pcm_file)
452 return -ENOTTY;
453 substream = pcm_file->substream;
454 if (! substream)
455 return -ENOTTY;
456
457 /*
458 * When PCM is used on 32bit mode, we need to disable
459 * mmap of PCM status/control records because of the size
460 * incompatibility.
461 */
462 substream->no_mmap_ctrl = 1;
463
464 switch (cmd) {
465 case SNDRV_PCM_IOCTL_PVERSION:
466 case SNDRV_PCM_IOCTL_INFO:
467 case SNDRV_PCM_IOCTL_TSTAMP:
468 case SNDRV_PCM_IOCTL_HWSYNC:
469 case SNDRV_PCM_IOCTL_PREPARE:
470 case SNDRV_PCM_IOCTL_RESET:
471 case SNDRV_PCM_IOCTL_START:
472 case SNDRV_PCM_IOCTL_DROP:
473 case SNDRV_PCM_IOCTL_DRAIN:
474 case SNDRV_PCM_IOCTL_PAUSE:
475 case SNDRV_PCM_IOCTL_HW_FREE:
476 case SNDRV_PCM_IOCTL_RESUME:
477 case SNDRV_PCM_IOCTL_XRUN:
478 case SNDRV_PCM_IOCTL_LINK:
479 case SNDRV_PCM_IOCTL_UNLINK:
480 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
481 return snd_pcm_playback_ioctl1(substream, cmd, argp);
482 else
483 return snd_pcm_capture_ioctl1(substream, cmd, argp);
484 case SNDRV_PCM_IOCTL_HW_REFINE32:
485 return snd_pcm_ioctl_hw_params_compat(substream, 1, argp);
486 case SNDRV_PCM_IOCTL_HW_PARAMS32:
487 return snd_pcm_ioctl_hw_params_compat(substream, 0, argp);
488 case SNDRV_PCM_IOCTL_SW_PARAMS32:
489 return snd_pcm_ioctl_sw_params_compat(substream, argp);
490 case SNDRV_PCM_IOCTL_STATUS32:
491 return snd_pcm_status_user_compat(substream, argp);
492 case SNDRV_PCM_IOCTL_SYNC_PTR32:
493 return snd_pcm_ioctl_sync_ptr_compat(substream, argp);
494 case SNDRV_PCM_IOCTL_CHANNEL_INFO32:
495 return snd_pcm_ioctl_channel_info_compat(substream, argp);
496 case SNDRV_PCM_IOCTL_WRITEI_FRAMES32:
497 return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
498 case SNDRV_PCM_IOCTL_READI_FRAMES32:
499 return snd_pcm_ioctl_xferi_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
500 case SNDRV_PCM_IOCTL_WRITEN_FRAMES32:
501 return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_PLAYBACK, argp);
502 case SNDRV_PCM_IOCTL_READN_FRAMES32:
503 return snd_pcm_ioctl_xfern_compat(substream, SNDRV_PCM_STREAM_CAPTURE, argp);
504 case SNDRV_PCM_IOCTL_DELAY32:
505 return snd_pcm_ioctl_delay_compat(substream, argp);
506 case SNDRV_PCM_IOCTL_REWIND32:
507 return snd_pcm_ioctl_rewind_compat(substream, argp);
508 case SNDRV_PCM_IOCTL_FORWARD32:
509 return snd_pcm_ioctl_forward_compat(substream, argp);
510 }
511
512 return -ENOIOCTLCMD;
513}
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
new file mode 100644
index 000000000000..151fd99ca2c9
--- /dev/null
+++ b/sound/core/pcm_lib.c
@@ -0,0 +1,2612 @@
1/*
2 * Digital Audio (PCM) abstract layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 * Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <linux/slab.h>
25#include <linux/time.h>
26#include <sound/core.h>
27#include <sound/control.h>
28#include <sound/info.h>
29#include <sound/pcm.h>
30#include <sound/pcm_params.h>
31#include <sound/timer.h>
32
33/*
34 * fill ring buffer with silence
35 * runtime->silence_start: starting pointer to silence area
36 * runtime->silence_filled: size filled with silence
37 * runtime->silence_threshold: threshold from application
38 * runtime->silence_size: maximal size from application
39 *
40 * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
41 */
42void snd_pcm_playback_silence(snd_pcm_substream_t *substream, snd_pcm_uframes_t new_hw_ptr)
43{
44 snd_pcm_runtime_t *runtime = substream->runtime;
45 snd_pcm_uframes_t frames, ofs, transfer;
46
47 if (runtime->silence_size < runtime->boundary) {
48 snd_pcm_sframes_t noise_dist, n;
49 if (runtime->silence_start != runtime->control->appl_ptr) {
50 n = runtime->control->appl_ptr - runtime->silence_start;
51 if (n < 0)
52 n += runtime->boundary;
53 if ((snd_pcm_uframes_t)n < runtime->silence_filled)
54 runtime->silence_filled -= n;
55 else
56 runtime->silence_filled = 0;
57 runtime->silence_start = runtime->control->appl_ptr;
58 }
59 if (runtime->silence_filled == runtime->buffer_size)
60 return;
61 snd_assert(runtime->silence_filled <= runtime->buffer_size, return);
62 noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
63 if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
64 return;
65 frames = runtime->silence_threshold - noise_dist;
66 if (frames > runtime->silence_size)
67 frames = runtime->silence_size;
68 } else {
69 if (new_hw_ptr == ULONG_MAX) { /* initialization */
70 snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
71 runtime->silence_filled = avail > 0 ? avail : 0;
72 runtime->silence_start = (runtime->status->hw_ptr +
73 runtime->silence_filled) %
74 runtime->boundary;
75 } else {
76 ofs = runtime->status->hw_ptr;
77 frames = new_hw_ptr - ofs;
78 if ((snd_pcm_sframes_t)frames < 0)
79 frames += runtime->boundary;
80 runtime->silence_filled -= frames;
81 if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
82 runtime->silence_filled = 0;
83 runtime->silence_start = (ofs + frames) - runtime->buffer_size;
84 } else {
85 runtime->silence_start = ofs - runtime->silence_filled;
86 }
87 if ((snd_pcm_sframes_t)runtime->silence_start < 0)
88 runtime->silence_start += runtime->boundary;
89 }
90 frames = runtime->buffer_size - runtime->silence_filled;
91 }
92 snd_assert(frames <= runtime->buffer_size, return);
93 if (frames == 0)
94 return;
95 ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
96 while (frames > 0) {
97 transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
98 if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
99 runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
100 if (substream->ops->silence) {
101 int err;
102 err = substream->ops->silence(substream, -1, ofs, transfer);
103 snd_assert(err >= 0, );
104 } else {
105 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
106 snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
107 }
108 } else {
109 unsigned int c;
110 unsigned int channels = runtime->channels;
111 if (substream->ops->silence) {
112 for (c = 0; c < channels; ++c) {
113 int err;
114 err = substream->ops->silence(substream, c, ofs, transfer);
115 snd_assert(err >= 0, );
116 }
117 } else {
118 size_t dma_csize = runtime->dma_bytes / channels;
119 for (c = 0; c < channels; ++c) {
120 char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
121 snd_pcm_format_set_silence(runtime->format, hwbuf, transfer);
122 }
123 }
124 }
125 runtime->silence_filled += transfer;
126 frames -= transfer;
127 ofs = 0;
128 }
129}
130
131static void xrun(snd_pcm_substream_t *substream)
132{
133 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
134#ifdef CONFIG_SND_DEBUG
135 if (substream->pstr->xrun_debug) {
136 snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
137 substream->pcm->card->number,
138 substream->pcm->device,
139 substream->stream ? 'c' : 'p');
140 if (substream->pstr->xrun_debug > 1)
141 dump_stack();
142 }
143#endif
144}
145
146static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(snd_pcm_substream_t *substream,
147 snd_pcm_runtime_t *runtime)
148{
149 snd_pcm_uframes_t pos;
150
151 pos = substream->ops->pointer(substream);
152 if (pos == SNDRV_PCM_POS_XRUN)
153 return pos; /* XRUN */
154 if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
155 snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec);
156#ifdef CONFIG_SND_DEBUG
157 if (pos >= runtime->buffer_size) {
158 snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
159 } else
160#endif
161 snd_runtime_check(pos < runtime->buffer_size, return 0);
162 pos -= pos % runtime->min_align;
163 return pos;
164}
165
166static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream,
167 snd_pcm_runtime_t *runtime)
168{
169 snd_pcm_uframes_t avail;
170
171 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
172 avail = snd_pcm_playback_avail(runtime);
173 else
174 avail = snd_pcm_capture_avail(runtime);
175 if (avail > runtime->avail_max)
176 runtime->avail_max = avail;
177 if (avail >= runtime->stop_threshold) {
178 if (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING)
179 snd_pcm_drain_done(substream);
180 else
181 xrun(substream);
182 return -EPIPE;
183 }
184 if (avail >= runtime->control->avail_min)
185 wake_up(&runtime->sleep);
186 return 0;
187}
188
189static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream)
190{
191 snd_pcm_runtime_t *runtime = substream->runtime;
192 snd_pcm_uframes_t pos;
193 snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt;
194 snd_pcm_sframes_t delta;
195
196 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
197 if (pos == SNDRV_PCM_POS_XRUN) {
198 xrun(substream);
199 return -EPIPE;
200 }
201 if (runtime->period_size == runtime->buffer_size)
202 goto __next_buf;
203 new_hw_ptr = runtime->hw_ptr_base + pos;
204 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
205
206 delta = hw_ptr_interrupt - new_hw_ptr;
207 if (delta > 0) {
208 if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
209#ifdef CONFIG_SND_DEBUG
210 if (runtime->periods > 1 && substream->pstr->xrun_debug) {
211 snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
212 if (substream->pstr->xrun_debug > 1)
213 dump_stack();
214 }
215#endif
216 return 0;
217 }
218 __next_buf:
219 runtime->hw_ptr_base += runtime->buffer_size;
220 if (runtime->hw_ptr_base == runtime->boundary)
221 runtime->hw_ptr_base = 0;
222 new_hw_ptr = runtime->hw_ptr_base + pos;
223 }
224
225 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
226 runtime->silence_size > 0)
227 snd_pcm_playback_silence(substream, new_hw_ptr);
228
229 runtime->status->hw_ptr = new_hw_ptr;
230 runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size;
231
232 return snd_pcm_update_hw_ptr_post(substream, runtime);
233}
234
235/* CAUTION: call it with irq disabled */
236int snd_pcm_update_hw_ptr(snd_pcm_substream_t *substream)
237{
238 snd_pcm_runtime_t *runtime = substream->runtime;
239 snd_pcm_uframes_t pos;
240 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr;
241 snd_pcm_sframes_t delta;
242
243 old_hw_ptr = runtime->status->hw_ptr;
244 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
245 if (pos == SNDRV_PCM_POS_XRUN) {
246 xrun(substream);
247 return -EPIPE;
248 }
249 new_hw_ptr = runtime->hw_ptr_base + pos;
250
251 delta = old_hw_ptr - new_hw_ptr;
252 if (delta > 0) {
253 if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
254#ifdef CONFIG_SND_DEBUG
255 if (runtime->periods > 2 && substream->pstr->xrun_debug) {
256 snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
257 if (substream->pstr->xrun_debug > 1)
258 dump_stack();
259 }
260#endif
261 return 0;
262 }
263 runtime->hw_ptr_base += runtime->buffer_size;
264 if (runtime->hw_ptr_base == runtime->boundary)
265 runtime->hw_ptr_base = 0;
266 new_hw_ptr = runtime->hw_ptr_base + pos;
267 }
268 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
269 runtime->silence_size > 0)
270 snd_pcm_playback_silence(substream, new_hw_ptr);
271
272 runtime->status->hw_ptr = new_hw_ptr;
273
274 return snd_pcm_update_hw_ptr_post(substream, runtime);
275}
276
277/**
278 * snd_pcm_set_ops - set the PCM operators
279 * @pcm: the pcm instance
280 * @direction: stream direction, SNDRV_PCM_STREAM_XXX
281 * @ops: the operator table
282 *
283 * Sets the given PCM operators to the pcm instance.
284 */
285void snd_pcm_set_ops(snd_pcm_t *pcm, int direction, snd_pcm_ops_t *ops)
286{
287 snd_pcm_str_t *stream = &pcm->streams[direction];
288 snd_pcm_substream_t *substream;
289
290 for (substream = stream->substream; substream != NULL; substream = substream->next)
291 substream->ops = ops;
292}
293
294
295/**
296 * snd_pcm_sync - set the PCM sync id
297 * @substream: the pcm substream
298 *
299 * Sets the PCM sync identifier for the card.
300 */
301void snd_pcm_set_sync(snd_pcm_substream_t * substream)
302{
303 snd_pcm_runtime_t *runtime = substream->runtime;
304
305 runtime->sync.id32[0] = substream->pcm->card->number;
306 runtime->sync.id32[1] = -1;
307 runtime->sync.id32[2] = -1;
308 runtime->sync.id32[3] = -1;
309}
310
311/*
312 * Standard ioctl routine
313 */
314
315/* Code taken from alsa-lib */
316#define assert(a) snd_assert((a), return -EINVAL)
317
318static inline unsigned int div32(unsigned int a, unsigned int b,
319 unsigned int *r)
320{
321 if (b == 0) {
322 *r = 0;
323 return UINT_MAX;
324 }
325 *r = a % b;
326 return a / b;
327}
328
329static inline unsigned int div_down(unsigned int a, unsigned int b)
330{
331 if (b == 0)
332 return UINT_MAX;
333 return a / b;
334}
335
336static inline unsigned int div_up(unsigned int a, unsigned int b)
337{
338 unsigned int r;
339 unsigned int q;
340 if (b == 0)
341 return UINT_MAX;
342 q = div32(a, b, &r);
343 if (r)
344 ++q;
345 return q;
346}
347
348static inline unsigned int mul(unsigned int a, unsigned int b)
349{
350 if (a == 0)
351 return 0;
352 if (div_down(UINT_MAX, a) < b)
353 return UINT_MAX;
354 return a * b;
355}
356
357static inline unsigned int muldiv32(unsigned int a, unsigned int b,
358 unsigned int c, unsigned int *r)
359{
360 u_int64_t n = (u_int64_t) a * b;
361 if (c == 0) {
362 snd_assert(n > 0, );
363 *r = 0;
364 return UINT_MAX;
365 }
366 div64_32(&n, c, r);
367 if (n >= UINT_MAX) {
368 *r = 0;
369 return UINT_MAX;
370 }
371 return n;
372}
373
374static int snd_interval_refine_min(snd_interval_t *i, unsigned int min, int openmin)
375{
376 int changed = 0;
377 assert(!snd_interval_empty(i));
378 if (i->min < min) {
379 i->min = min;
380 i->openmin = openmin;
381 changed = 1;
382 } else if (i->min == min && !i->openmin && openmin) {
383 i->openmin = 1;
384 changed = 1;
385 }
386 if (i->integer) {
387 if (i->openmin) {
388 i->min++;
389 i->openmin = 0;
390 }
391 }
392 if (snd_interval_checkempty(i)) {
393 snd_interval_none(i);
394 return -EINVAL;
395 }
396 return changed;
397}
398
399static int snd_interval_refine_max(snd_interval_t *i, unsigned int max, int openmax)
400{
401 int changed = 0;
402 assert(!snd_interval_empty(i));
403 if (i->max > max) {
404 i->max = max;
405 i->openmax = openmax;
406 changed = 1;
407 } else if (i->max == max && !i->openmax && openmax) {
408 i->openmax = 1;
409 changed = 1;
410 }
411 if (i->integer) {
412 if (i->openmax) {
413 i->max--;
414 i->openmax = 0;
415 }
416 }
417 if (snd_interval_checkempty(i)) {
418 snd_interval_none(i);
419 return -EINVAL;
420 }
421 return changed;
422}
423
424/**
425 * snd_interval_refine - refine the interval value of configurator
426 * @i: the interval value to refine
427 * @v: the interval value to refer to
428 *
429 * Refines the interval value with the reference value.
430 * The interval is changed to the range satisfying both intervals.
431 * The interval status (min, max, integer, etc.) are evaluated.
432 *
433 * Returns non-zero if the value is changed, zero if not changed.
434 */
435int snd_interval_refine(snd_interval_t *i, const snd_interval_t *v)
436{
437 int changed = 0;
438 assert(!snd_interval_empty(i));
439 if (i->min < v->min) {
440 i->min = v->min;
441 i->openmin = v->openmin;
442 changed = 1;
443 } else if (i->min == v->min && !i->openmin && v->openmin) {
444 i->openmin = 1;
445 changed = 1;
446 }
447 if (i->max > v->max) {
448 i->max = v->max;
449 i->openmax = v->openmax;
450 changed = 1;
451 } else if (i->max == v->max && !i->openmax && v->openmax) {
452 i->openmax = 1;
453 changed = 1;
454 }
455 if (!i->integer && v->integer) {
456 i->integer = 1;
457 changed = 1;
458 }
459 if (i->integer) {
460 if (i->openmin) {
461 i->min++;
462 i->openmin = 0;
463 }
464 if (i->openmax) {
465 i->max--;
466 i->openmax = 0;
467 }
468 } else if (!i->openmin && !i->openmax && i->min == i->max)
469 i->integer = 1;
470 if (snd_interval_checkempty(i)) {
471 snd_interval_none(i);
472 return -EINVAL;
473 }
474 return changed;
475}
476
477static int snd_interval_refine_first(snd_interval_t *i)
478{
479 assert(!snd_interval_empty(i));
480 if (snd_interval_single(i))
481 return 0;
482 i->max = i->min;
483 i->openmax = i->openmin;
484 if (i->openmax)
485 i->max++;
486 return 1;
487}
488
489static int snd_interval_refine_last(snd_interval_t *i)
490{
491 assert(!snd_interval_empty(i));
492 if (snd_interval_single(i))
493 return 0;
494 i->min = i->max;
495 i->openmin = i->openmax;
496 if (i->openmin)
497 i->min--;
498 return 1;
499}
500
501static int snd_interval_refine_set(snd_interval_t *i, unsigned int val)
502{
503 snd_interval_t t;
504 t.empty = 0;
505 t.min = t.max = val;
506 t.openmin = t.openmax = 0;
507 t.integer = 1;
508 return snd_interval_refine(i, &t);
509}
510
511void snd_interval_mul(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c)
512{
513 if (a->empty || b->empty) {
514 snd_interval_none(c);
515 return;
516 }
517 c->empty = 0;
518 c->min = mul(a->min, b->min);
519 c->openmin = (a->openmin || b->openmin);
520 c->max = mul(a->max, b->max);
521 c->openmax = (a->openmax || b->openmax);
522 c->integer = (a->integer && b->integer);
523}
524
525/**
526 * snd_interval_div - refine the interval value with division
527 *
528 * c = a / b
529 *
530 * Returns non-zero if the value is changed, zero if not changed.
531 */
532void snd_interval_div(const snd_interval_t *a, const snd_interval_t *b, snd_interval_t *c)
533{
534 unsigned int r;
535 if (a->empty || b->empty) {
536 snd_interval_none(c);
537 return;
538 }
539 c->empty = 0;
540 c->min = div32(a->min, b->max, &r);
541 c->openmin = (r || a->openmin || b->openmax);
542 if (b->min > 0) {
543 c->max = div32(a->max, b->min, &r);
544 if (r) {
545 c->max++;
546 c->openmax = 1;
547 } else
548 c->openmax = (a->openmax || b->openmin);
549 } else {
550 c->max = UINT_MAX;
551 c->openmax = 0;
552 }
553 c->integer = 0;
554}
555
556/**
557 * snd_interval_muldivk - refine the interval value
558 *
559 * c = a * b / k
560 *
561 * Returns non-zero if the value is changed, zero if not changed.
562 */
563void snd_interval_muldivk(const snd_interval_t *a, const snd_interval_t *b,
564 unsigned int k, snd_interval_t *c)
565{
566 unsigned int r;
567 if (a->empty || b->empty) {
568 snd_interval_none(c);
569 return;
570 }
571 c->empty = 0;
572 c->min = muldiv32(a->min, b->min, k, &r);
573 c->openmin = (r || a->openmin || b->openmin);
574 c->max = muldiv32(a->max, b->max, k, &r);
575 if (r) {
576 c->max++;
577 c->openmax = 1;
578 } else
579 c->openmax = (a->openmax || b->openmax);
580 c->integer = 0;
581}
582
583/**
584 * snd_interval_mulkdiv - refine the interval value
585 *
586 * c = a * k / b
587 *
588 * Returns non-zero if the value is changed, zero if not changed.
589 */
590void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k,
591 const snd_interval_t *b, snd_interval_t *c)
592{
593 unsigned int r;
594 if (a->empty || b->empty) {
595 snd_interval_none(c);
596 return;
597 }
598 c->empty = 0;
599 c->min = muldiv32(a->min, k, b->max, &r);
600 c->openmin = (r || a->openmin || b->openmax);
601 if (b->min > 0) {
602 c->max = muldiv32(a->max, k, b->min, &r);
603 if (r) {
604 c->max++;
605 c->openmax = 1;
606 } else
607 c->openmax = (a->openmax || b->openmin);
608 } else {
609 c->max = UINT_MAX;
610 c->openmax = 0;
611 }
612 c->integer = 0;
613}
614
615#undef assert
616/* ---- */
617
618
619/**
620 * snd_interval_ratnum - refine the interval value
621 *
622 * Returns non-zero if the value is changed, zero if not changed.
623 */
624int snd_interval_ratnum(snd_interval_t *i,
625 unsigned int rats_count, ratnum_t *rats,
626 unsigned int *nump, unsigned int *denp)
627{
628 unsigned int best_num, best_diff, best_den;
629 unsigned int k;
630 snd_interval_t t;
631 int err;
632
633 best_num = best_den = best_diff = 0;
634 for (k = 0; k < rats_count; ++k) {
635 unsigned int num = rats[k].num;
636 unsigned int den;
637 unsigned int q = i->min;
638 int diff;
639 if (q == 0)
640 q = 1;
641 den = div_down(num, q);
642 if (den < rats[k].den_min)
643 continue;
644 if (den > rats[k].den_max)
645 den = rats[k].den_max;
646 else {
647 unsigned int r;
648 r = (den - rats[k].den_min) % rats[k].den_step;
649 if (r != 0)
650 den -= r;
651 }
652 diff = num - q * den;
653 if (best_num == 0 ||
654 diff * best_den < best_diff * den) {
655 best_diff = diff;
656 best_den = den;
657 best_num = num;
658 }
659 }
660 if (best_den == 0) {
661 i->empty = 1;
662 return -EINVAL;
663 }
664 t.min = div_down(best_num, best_den);
665 t.openmin = !!(best_num % best_den);
666
667 best_num = best_den = best_diff = 0;
668 for (k = 0; k < rats_count; ++k) {
669 unsigned int num = rats[k].num;
670 unsigned int den;
671 unsigned int q = i->max;
672 int diff;
673 if (q == 0) {
674 i->empty = 1;
675 return -EINVAL;
676 }
677 den = div_up(num, q);
678 if (den > rats[k].den_max)
679 continue;
680 if (den < rats[k].den_min)
681 den = rats[k].den_min;
682 else {
683 unsigned int r;
684 r = (den - rats[k].den_min) % rats[k].den_step;
685 if (r != 0)
686 den += rats[k].den_step - r;
687 }
688 diff = q * den - num;
689 if (best_num == 0 ||
690 diff * best_den < best_diff * den) {
691 best_diff = diff;
692 best_den = den;
693 best_num = num;
694 }
695 }
696 if (best_den == 0) {
697 i->empty = 1;
698 return -EINVAL;
699 }
700 t.max = div_up(best_num, best_den);
701 t.openmax = !!(best_num % best_den);
702 t.integer = 0;
703 err = snd_interval_refine(i, &t);
704 if (err < 0)
705 return err;
706
707 if (snd_interval_single(i)) {
708 if (nump)
709 *nump = best_num;
710 if (denp)
711 *denp = best_den;
712 }
713 return err;
714}
715
716/**
717 * snd_interval_ratden - refine the interval value
718 *
719 * Returns non-zero if the value is changed, zero if not changed.
720 */
721static int snd_interval_ratden(snd_interval_t *i,
722 unsigned int rats_count, ratden_t *rats,
723 unsigned int *nump, unsigned int *denp)
724{
725 unsigned int best_num, best_diff, best_den;
726 unsigned int k;
727 snd_interval_t t;
728 int err;
729
730 best_num = best_den = best_diff = 0;
731 for (k = 0; k < rats_count; ++k) {
732 unsigned int num;
733 unsigned int den = rats[k].den;
734 unsigned int q = i->min;
735 int diff;
736 num = mul(q, den);
737 if (num > rats[k].num_max)
738 continue;
739 if (num < rats[k].num_min)
740 num = rats[k].num_max;
741 else {
742 unsigned int r;
743 r = (num - rats[k].num_min) % rats[k].num_step;
744 if (r != 0)
745 num += rats[k].num_step - r;
746 }
747 diff = num - q * den;
748 if (best_num == 0 ||
749 diff * best_den < best_diff * den) {
750 best_diff = diff;
751 best_den = den;
752 best_num = num;
753 }
754 }
755 if (best_den == 0) {
756 i->empty = 1;
757 return -EINVAL;
758 }
759 t.min = div_down(best_num, best_den);
760 t.openmin = !!(best_num % best_den);
761
762 best_num = best_den = best_diff = 0;
763 for (k = 0; k < rats_count; ++k) {
764 unsigned int num;
765 unsigned int den = rats[k].den;
766 unsigned int q = i->max;
767 int diff;
768 num = mul(q, den);
769 if (num < rats[k].num_min)
770 continue;
771 if (num > rats[k].num_max)
772 num = rats[k].num_max;
773 else {
774 unsigned int r;
775 r = (num - rats[k].num_min) % rats[k].num_step;
776 if (r != 0)
777 num -= r;
778 }
779 diff = q * den - num;
780 if (best_num == 0 ||
781 diff * best_den < best_diff * den) {
782 best_diff = diff;
783 best_den = den;
784 best_num = num;
785 }
786 }
787 if (best_den == 0) {
788 i->empty = 1;
789 return -EINVAL;
790 }
791 t.max = div_up(best_num, best_den);
792 t.openmax = !!(best_num % best_den);
793 t.integer = 0;
794 err = snd_interval_refine(i, &t);
795 if (err < 0)
796 return err;
797
798 if (snd_interval_single(i)) {
799 if (nump)
800 *nump = best_num;
801 if (denp)
802 *denp = best_den;
803 }
804 return err;
805}
806
807/**
808 * snd_interval_list - refine the interval value from the list
809 * @i: the interval value to refine
810 * @count: the number of elements in the list
811 * @list: the value list
812 * @mask: the bit-mask to evaluate
813 *
814 * Refines the interval value from the list.
815 * When mask is non-zero, only the elements corresponding to bit 1 are
816 * evaluated.
817 *
818 * Returns non-zero if the value is changed, zero if not changed.
819 */
820int snd_interval_list(snd_interval_t *i, unsigned int count, unsigned int *list, unsigned int mask)
821{
822 unsigned int k;
823 int changed = 0;
824 for (k = 0; k < count; k++) {
825 if (mask && !(mask & (1 << k)))
826 continue;
827 if (i->min == list[k] && !i->openmin)
828 goto _l1;
829 if (i->min < list[k]) {
830 i->min = list[k];
831 i->openmin = 0;
832 changed = 1;
833 goto _l1;
834 }
835 }
836 i->empty = 1;
837 return -EINVAL;
838 _l1:
839 for (k = count; k-- > 0;) {
840 if (mask && !(mask & (1 << k)))
841 continue;
842 if (i->max == list[k] && !i->openmax)
843 goto _l2;
844 if (i->max > list[k]) {
845 i->max = list[k];
846 i->openmax = 0;
847 changed = 1;
848 goto _l2;
849 }
850 }
851 i->empty = 1;
852 return -EINVAL;
853 _l2:
854 if (snd_interval_checkempty(i)) {
855 i->empty = 1;
856 return -EINVAL;
857 }
858 return changed;
859}
860
861static int snd_interval_step(snd_interval_t *i, unsigned int min, unsigned int step)
862{
863 unsigned int n;
864 int changed = 0;
865 n = (i->min - min) % step;
866 if (n != 0 || i->openmin) {
867 i->min += step - n;
868 changed = 1;
869 }
870 n = (i->max - min) % step;
871 if (n != 0 || i->openmax) {
872 i->max -= n;
873 changed = 1;
874 }
875 if (snd_interval_checkempty(i)) {
876 i->empty = 1;
877 return -EINVAL;
878 }
879 return changed;
880}
881
882/* Info constraints helpers */
883
884/**
885 * snd_pcm_hw_rule_add - add the hw-constraint rule
886 * @runtime: the pcm runtime instance
887 * @cond: condition bits
888 * @var: the variable to evaluate
889 * @func: the evaluation function
890 * @private: the private data pointer passed to function
891 * @dep: the dependent variables
892 *
893 * Returns zero if successful, or a negative error code on failure.
894 */
895int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime, unsigned int cond,
896 int var,
897 snd_pcm_hw_rule_func_t func, void *private,
898 int dep, ...)
899{
900 snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
901 snd_pcm_hw_rule_t *c;
902 unsigned int k;
903 va_list args;
904 va_start(args, dep);
905 if (constrs->rules_num >= constrs->rules_all) {
906 snd_pcm_hw_rule_t *new;
907 unsigned int new_rules = constrs->rules_all + 16;
908 new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
909 if (!new)
910 return -ENOMEM;
911 if (constrs->rules) {
912 memcpy(new, constrs->rules,
913 constrs->rules_num * sizeof(*c));
914 kfree(constrs->rules);
915 }
916 constrs->rules = new;
917 constrs->rules_all = new_rules;
918 }
919 c = &constrs->rules[constrs->rules_num];
920 c->cond = cond;
921 c->func = func;
922 c->var = var;
923 c->private = private;
924 k = 0;
925 while (1) {
926 snd_assert(k < ARRAY_SIZE(c->deps), return -EINVAL);
927 c->deps[k++] = dep;
928 if (dep < 0)
929 break;
930 dep = va_arg(args, int);
931 }
932 constrs->rules_num++;
933 va_end(args);
934 return 0;
935}
936
937/**
938 * snd_pcm_hw_constraint_mask
939 */
940int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
941 u_int32_t mask)
942{
943 snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
944 snd_mask_t *maskp = constrs_mask(constrs, var);
945 *maskp->bits &= mask;
946 memset(maskp->bits + 1, 0, (SNDRV_MASK_MAX-32) / 8); /* clear rest */
947 if (*maskp->bits == 0)
948 return -EINVAL;
949 return 0;
950}
951
952/**
953 * snd_pcm_hw_constraint_mask64
954 */
955int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
956 u_int64_t mask)
957{
958 snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
959 snd_mask_t *maskp = constrs_mask(constrs, var);
960 maskp->bits[0] &= (u_int32_t)mask;
961 maskp->bits[1] &= (u_int32_t)(mask >> 32);
962 memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
963 if (! maskp->bits[0] && ! maskp->bits[1])
964 return -EINVAL;
965 return 0;
966}
967
968/**
969 * snd_pcm_hw_constraint_integer
970 */
971int snd_pcm_hw_constraint_integer(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var)
972{
973 snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
974 return snd_interval_setinteger(constrs_interval(constrs, var));
975}
976
977/**
978 * snd_pcm_hw_constraint_minmax
979 */
980int snd_pcm_hw_constraint_minmax(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var,
981 unsigned int min, unsigned int max)
982{
983 snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
984 snd_interval_t t;
985 t.min = min;
986 t.max = max;
987 t.openmin = t.openmax = 0;
988 t.integer = 0;
989 return snd_interval_refine(constrs_interval(constrs, var), &t);
990}
991
992static int snd_pcm_hw_rule_list(snd_pcm_hw_params_t *params,
993 snd_pcm_hw_rule_t *rule)
994{
995 snd_pcm_hw_constraint_list_t *list = rule->private;
996 return snd_interval_list(hw_param_interval(params, rule->var), list->count, list->list, list->mask);
997}
998
999
1000/**
1001 * snd_pcm_hw_constraint_list
1002 */
1003int snd_pcm_hw_constraint_list(snd_pcm_runtime_t *runtime,
1004 unsigned int cond,
1005 snd_pcm_hw_param_t var,
1006 snd_pcm_hw_constraint_list_t *l)
1007{
1008 return snd_pcm_hw_rule_add(runtime, cond, var,
1009 snd_pcm_hw_rule_list, l,
1010 var, -1);
1011}
1012
1013static int snd_pcm_hw_rule_ratnums(snd_pcm_hw_params_t *params,
1014 snd_pcm_hw_rule_t *rule)
1015{
1016 snd_pcm_hw_constraint_ratnums_t *r = rule->private;
1017 unsigned int num = 0, den = 0;
1018 int err;
1019 err = snd_interval_ratnum(hw_param_interval(params, rule->var),
1020 r->nrats, r->rats, &num, &den);
1021 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1022 params->rate_num = num;
1023 params->rate_den = den;
1024 }
1025 return err;
1026}
1027
1028/**
1029 * snd_pcm_hw_constraint_ratnums
1030 */
1031int snd_pcm_hw_constraint_ratnums(snd_pcm_runtime_t *runtime,
1032 unsigned int cond,
1033 snd_pcm_hw_param_t var,
1034 snd_pcm_hw_constraint_ratnums_t *r)
1035{
1036 return snd_pcm_hw_rule_add(runtime, cond, var,
1037 snd_pcm_hw_rule_ratnums, r,
1038 var, -1);
1039}
1040
1041static int snd_pcm_hw_rule_ratdens(snd_pcm_hw_params_t *params,
1042 snd_pcm_hw_rule_t *rule)
1043{
1044 snd_pcm_hw_constraint_ratdens_t *r = rule->private;
1045 unsigned int num = 0, den = 0;
1046 int err = snd_interval_ratden(hw_param_interval(params, rule->var),
1047 r->nrats, r->rats, &num, &den);
1048 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1049 params->rate_num = num;
1050 params->rate_den = den;
1051 }
1052 return err;
1053}
1054
1055/**
1056 * snd_pcm_hw_constraint_ratdens
1057 */
1058int snd_pcm_hw_constraint_ratdens(snd_pcm_runtime_t *runtime,
1059 unsigned int cond,
1060 snd_pcm_hw_param_t var,
1061 snd_pcm_hw_constraint_ratdens_t *r)
1062{
1063 return snd_pcm_hw_rule_add(runtime, cond, var,
1064 snd_pcm_hw_rule_ratdens, r,
1065 var, -1);
1066}
1067
1068static int snd_pcm_hw_rule_msbits(snd_pcm_hw_params_t *params,
1069 snd_pcm_hw_rule_t *rule)
1070{
1071 unsigned int l = (unsigned long) rule->private;
1072 int width = l & 0xffff;
1073 unsigned int msbits = l >> 16;
1074 snd_interval_t *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
1075 if (snd_interval_single(i) && snd_interval_value(i) == width)
1076 params->msbits = msbits;
1077 return 0;
1078}
1079
1080/**
1081 * snd_pcm_hw_constraint_msbits
1082 */
1083int snd_pcm_hw_constraint_msbits(snd_pcm_runtime_t *runtime,
1084 unsigned int cond,
1085 unsigned int width,
1086 unsigned int msbits)
1087{
1088 unsigned long l = (msbits << 16) | width;
1089 return snd_pcm_hw_rule_add(runtime, cond, -1,
1090 snd_pcm_hw_rule_msbits,
1091 (void*) l,
1092 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1093}
1094
1095static int snd_pcm_hw_rule_step(snd_pcm_hw_params_t *params,
1096 snd_pcm_hw_rule_t *rule)
1097{
1098 unsigned long step = (unsigned long) rule->private;
1099 return snd_interval_step(hw_param_interval(params, rule->var), 0, step);
1100}
1101
1102/**
1103 * snd_pcm_hw_constraint_step
1104 */
1105int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime,
1106 unsigned int cond,
1107 snd_pcm_hw_param_t var,
1108 unsigned long step)
1109{
1110 return snd_pcm_hw_rule_add(runtime, cond, var,
1111 snd_pcm_hw_rule_step, (void *) step,
1112 var, -1);
1113}
1114
1115static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule)
1116{
1117 static int pow2_sizes[] = {
1118 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1119 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1120 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
1121 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
1122 };
1123 return snd_interval_list(hw_param_interval(params, rule->var),
1124 ARRAY_SIZE(pow2_sizes), pow2_sizes, 0);
1125}
1126
1127/**
1128 * snd_pcm_hw_constraint_pow2
1129 */
1130int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime,
1131 unsigned int cond,
1132 snd_pcm_hw_param_t var)
1133{
1134 return snd_pcm_hw_rule_add(runtime, cond, var,
1135 snd_pcm_hw_rule_pow2, NULL,
1136 var, -1);
1137}
1138
1139/* To use the same code we have in alsa-lib */
1140#define snd_pcm_t snd_pcm_substream_t
1141#define assert(i) snd_assert((i), return -EINVAL)
1142#ifndef INT_MIN
1143#define INT_MIN ((int)((unsigned int)INT_MAX+1))
1144#endif
1145
1146void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, snd_pcm_hw_param_t var)
1147{
1148 if (hw_is_mask(var)) {
1149 snd_mask_any(hw_param_mask(params, var));
1150 params->cmask |= 1 << var;
1151 params->rmask |= 1 << var;
1152 return;
1153 }
1154 if (hw_is_interval(var)) {
1155 snd_interval_any(hw_param_interval(params, var));
1156 params->cmask |= 1 << var;
1157 params->rmask |= 1 << var;
1158 return;
1159 }
1160 snd_BUG();
1161}
1162
1163/**
1164 * snd_pcm_hw_param_any
1165 */
1166int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1167 snd_pcm_hw_param_t var)
1168{
1169 _snd_pcm_hw_param_any(params, var);
1170 return snd_pcm_hw_refine(pcm, params);
1171}
1172
1173void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params)
1174{
1175 unsigned int k;
1176 memset(params, 0, sizeof(*params));
1177 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
1178 _snd_pcm_hw_param_any(params, k);
1179 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
1180 _snd_pcm_hw_param_any(params, k);
1181 params->info = ~0U;
1182}
1183
1184/**
1185 * snd_pcm_hw_params_any
1186 *
1187 * Fill PARAMS with full configuration space boundaries
1188 */
1189int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1190{
1191 _snd_pcm_hw_params_any(params);
1192 return snd_pcm_hw_refine(pcm, params);
1193}
1194
1195/**
1196 * snd_pcm_hw_param_value
1197 *
1198 * Return the value for field PAR if it's fixed in configuration space
1199 * defined by PARAMS. Return -EINVAL otherwise
1200 */
1201int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params,
1202 snd_pcm_hw_param_t var, int *dir)
1203{
1204 if (hw_is_mask(var)) {
1205 const snd_mask_t *mask = hw_param_mask_c(params, var);
1206 if (!snd_mask_single(mask))
1207 return -EINVAL;
1208 if (dir)
1209 *dir = 0;
1210 return snd_mask_value(mask);
1211 }
1212 if (hw_is_interval(var)) {
1213 const snd_interval_t *i = hw_param_interval_c(params, var);
1214 if (!snd_interval_single(i))
1215 return -EINVAL;
1216 if (dir)
1217 *dir = i->openmin;
1218 return snd_interval_value(i);
1219 }
1220 assert(0);
1221 return -EINVAL;
1222}
1223
1224/**
1225 * snd_pcm_hw_param_value_min
1226 *
1227 * Return the minimum value for field PAR.
1228 */
1229unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params,
1230 snd_pcm_hw_param_t var, int *dir)
1231{
1232 if (hw_is_mask(var)) {
1233 if (dir)
1234 *dir = 0;
1235 return snd_mask_min(hw_param_mask_c(params, var));
1236 }
1237 if (hw_is_interval(var)) {
1238 const snd_interval_t *i = hw_param_interval_c(params, var);
1239 if (dir)
1240 *dir = i->openmin;
1241 return snd_interval_min(i);
1242 }
1243 assert(0);
1244 return -EINVAL;
1245}
1246
1247/**
1248 * snd_pcm_hw_param_value_max
1249 *
1250 * Return the maximum value for field PAR.
1251 */
1252unsigned int snd_pcm_hw_param_value_max(const snd_pcm_hw_params_t *params,
1253 snd_pcm_hw_param_t var, int *dir)
1254{
1255 if (hw_is_mask(var)) {
1256 if (dir)
1257 *dir = 0;
1258 return snd_mask_max(hw_param_mask_c(params, var));
1259 }
1260 if (hw_is_interval(var)) {
1261 const snd_interval_t *i = hw_param_interval_c(params, var);
1262 if (dir)
1263 *dir = - (int) i->openmax;
1264 return snd_interval_max(i);
1265 }
1266 assert(0);
1267 return -EINVAL;
1268}
1269
1270void _snd_pcm_hw_param_setempty(snd_pcm_hw_params_t *params,
1271 snd_pcm_hw_param_t var)
1272{
1273 if (hw_is_mask(var)) {
1274 snd_mask_none(hw_param_mask(params, var));
1275 params->cmask |= 1 << var;
1276 params->rmask |= 1 << var;
1277 } else if (hw_is_interval(var)) {
1278 snd_interval_none(hw_param_interval(params, var));
1279 params->cmask |= 1 << var;
1280 params->rmask |= 1 << var;
1281 } else {
1282 snd_BUG();
1283 }
1284}
1285
1286int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params,
1287 snd_pcm_hw_param_t var)
1288{
1289 int changed;
1290 assert(hw_is_interval(var));
1291 changed = snd_interval_setinteger(hw_param_interval(params, var));
1292 if (changed) {
1293 params->cmask |= 1 << var;
1294 params->rmask |= 1 << var;
1295 }
1296 return changed;
1297}
1298
1299/**
1300 * snd_pcm_hw_param_setinteger
1301 *
1302 * Inside configuration space defined by PARAMS remove from PAR all
1303 * non integer values. Reduce configuration space accordingly.
1304 * Return -EINVAL if the configuration space is empty
1305 */
1306int snd_pcm_hw_param_setinteger(snd_pcm_t *pcm,
1307 snd_pcm_hw_params_t *params,
1308 snd_pcm_hw_param_t var)
1309{
1310 int changed = _snd_pcm_hw_param_setinteger(params, var);
1311 if (changed < 0)
1312 return changed;
1313 if (params->rmask) {
1314 int err = snd_pcm_hw_refine(pcm, params);
1315 if (err < 0)
1316 return err;
1317 }
1318 return 0;
1319}
1320
1321int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params,
1322 snd_pcm_hw_param_t var)
1323{
1324 int changed;
1325 if (hw_is_mask(var))
1326 changed = snd_mask_refine_first(hw_param_mask(params, var));
1327 else if (hw_is_interval(var))
1328 changed = snd_interval_refine_first(hw_param_interval(params, var));
1329 else {
1330 assert(0);
1331 return -EINVAL;
1332 }
1333 if (changed) {
1334 params->cmask |= 1 << var;
1335 params->rmask |= 1 << var;
1336 }
1337 return changed;
1338}
1339
1340
1341/**
1342 * snd_pcm_hw_param_first
1343 *
1344 * Inside configuration space defined by PARAMS remove from PAR all
1345 * values > minimum. Reduce configuration space accordingly.
1346 * Return the minimum.
1347 */
1348int snd_pcm_hw_param_first(snd_pcm_t *pcm,
1349 snd_pcm_hw_params_t *params,
1350 snd_pcm_hw_param_t var, int *dir)
1351{
1352 int changed = _snd_pcm_hw_param_first(params, var);
1353 if (changed < 0)
1354 return changed;
1355 if (params->rmask) {
1356 int err = snd_pcm_hw_refine(pcm, params);
1357 assert(err >= 0);
1358 }
1359 return snd_pcm_hw_param_value(params, var, dir);
1360}
1361
1362int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params,
1363 snd_pcm_hw_param_t var)
1364{
1365 int changed;
1366 if (hw_is_mask(var))
1367 changed = snd_mask_refine_last(hw_param_mask(params, var));
1368 else if (hw_is_interval(var))
1369 changed = snd_interval_refine_last(hw_param_interval(params, var));
1370 else {
1371 assert(0);
1372 return -EINVAL;
1373 }
1374 if (changed) {
1375 params->cmask |= 1 << var;
1376 params->rmask |= 1 << var;
1377 }
1378 return changed;
1379}
1380
1381
1382/**
1383 * snd_pcm_hw_param_last
1384 *
1385 * Inside configuration space defined by PARAMS remove from PAR all
1386 * values < maximum. Reduce configuration space accordingly.
1387 * Return the maximum.
1388 */
1389int snd_pcm_hw_param_last(snd_pcm_t *pcm,
1390 snd_pcm_hw_params_t *params,
1391 snd_pcm_hw_param_t var, int *dir)
1392{
1393 int changed = _snd_pcm_hw_param_last(params, var);
1394 if (changed < 0)
1395 return changed;
1396 if (params->rmask) {
1397 int err = snd_pcm_hw_refine(pcm, params);
1398 assert(err >= 0);
1399 }
1400 return snd_pcm_hw_param_value(params, var, dir);
1401}
1402
1403int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params,
1404 snd_pcm_hw_param_t var, unsigned int val, int dir)
1405{
1406 int changed;
1407 int open = 0;
1408 if (dir) {
1409 if (dir > 0) {
1410 open = 1;
1411 } else if (dir < 0) {
1412 if (val > 0) {
1413 open = 1;
1414 val--;
1415 }
1416 }
1417 }
1418 if (hw_is_mask(var))
1419 changed = snd_mask_refine_min(hw_param_mask(params, var), val + !!open);
1420 else if (hw_is_interval(var))
1421 changed = snd_interval_refine_min(hw_param_interval(params, var), val, open);
1422 else {
1423 assert(0);
1424 return -EINVAL;
1425 }
1426 if (changed) {
1427 params->cmask |= 1 << var;
1428 params->rmask |= 1 << var;
1429 }
1430 return changed;
1431}
1432
1433/**
1434 * snd_pcm_hw_param_min
1435 *
1436 * Inside configuration space defined by PARAMS remove from PAR all
1437 * values < VAL. Reduce configuration space accordingly.
1438 * Return new minimum or -EINVAL if the configuration space is empty
1439 */
1440int snd_pcm_hw_param_min(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1441 snd_pcm_hw_param_t var, unsigned int val, int *dir)
1442{
1443 int changed = _snd_pcm_hw_param_min(params, var, val, dir ? *dir : 0);
1444 if (changed < 0)
1445 return changed;
1446 if (params->rmask) {
1447 int err = snd_pcm_hw_refine(pcm, params);
1448 if (err < 0)
1449 return err;
1450 }
1451 return snd_pcm_hw_param_value_min(params, var, dir);
1452}
1453
1454int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params,
1455 snd_pcm_hw_param_t var, unsigned int val, int dir)
1456{
1457 int changed;
1458 int open = 0;
1459 if (dir) {
1460 if (dir < 0) {
1461 open = 1;
1462 } else if (dir > 0) {
1463 open = 1;
1464 val++;
1465 }
1466 }
1467 if (hw_is_mask(var)) {
1468 if (val == 0 && open) {
1469 snd_mask_none(hw_param_mask(params, var));
1470 changed = -EINVAL;
1471 } else
1472 changed = snd_mask_refine_max(hw_param_mask(params, var), val - !!open);
1473 } else if (hw_is_interval(var))
1474 changed = snd_interval_refine_max(hw_param_interval(params, var), val, open);
1475 else {
1476 assert(0);
1477 return -EINVAL;
1478 }
1479 if (changed) {
1480 params->cmask |= 1 << var;
1481 params->rmask |= 1 << var;
1482 }
1483 return changed;
1484}
1485
1486/**
1487 * snd_pcm_hw_param_max
1488 *
1489 * Inside configuration space defined by PARAMS remove from PAR all
1490 * values >= VAL + 1. Reduce configuration space accordingly.
1491 * Return new maximum or -EINVAL if the configuration space is empty
1492 */
1493int snd_pcm_hw_param_max(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1494 snd_pcm_hw_param_t var, unsigned int val, int *dir)
1495{
1496 int changed = _snd_pcm_hw_param_max(params, var, val, dir ? *dir : 0);
1497 if (changed < 0)
1498 return changed;
1499 if (params->rmask) {
1500 int err = snd_pcm_hw_refine(pcm, params);
1501 if (err < 0)
1502 return err;
1503 }
1504 return snd_pcm_hw_param_value_max(params, var, dir);
1505}
1506
1507int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params,
1508 snd_pcm_hw_param_t var, unsigned int val, int dir)
1509{
1510 int changed;
1511 if (hw_is_mask(var)) {
1512 snd_mask_t *m = hw_param_mask(params, var);
1513 if (val == 0 && dir < 0) {
1514 changed = -EINVAL;
1515 snd_mask_none(m);
1516 } else {
1517 if (dir > 0)
1518 val++;
1519 else if (dir < 0)
1520 val--;
1521 changed = snd_mask_refine_set(hw_param_mask(params, var), val);
1522 }
1523 } else if (hw_is_interval(var)) {
1524 snd_interval_t *i = hw_param_interval(params, var);
1525 if (val == 0 && dir < 0) {
1526 changed = -EINVAL;
1527 snd_interval_none(i);
1528 } else if (dir == 0)
1529 changed = snd_interval_refine_set(i, val);
1530 else {
1531 snd_interval_t t;
1532 t.openmin = 1;
1533 t.openmax = 1;
1534 t.empty = 0;
1535 t.integer = 0;
1536 if (dir < 0) {
1537 t.min = val - 1;
1538 t.max = val;
1539 } else {
1540 t.min = val;
1541 t.max = val+1;
1542 }
1543 changed = snd_interval_refine(i, &t);
1544 }
1545 } else {
1546 assert(0);
1547 return -EINVAL;
1548 }
1549 if (changed) {
1550 params->cmask |= 1 << var;
1551 params->rmask |= 1 << var;
1552 }
1553 return changed;
1554}
1555
1556/**
1557 * snd_pcm_hw_param_set
1558 *
1559 * Inside configuration space defined by PARAMS remove from PAR all
1560 * values != VAL. Reduce configuration space accordingly.
1561 * Return VAL or -EINVAL if the configuration space is empty
1562 */
1563int snd_pcm_hw_param_set(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1564 snd_pcm_hw_param_t var, unsigned int val, int dir)
1565{
1566 int changed = _snd_pcm_hw_param_set(params, var, val, dir);
1567 if (changed < 0)
1568 return changed;
1569 if (params->rmask) {
1570 int err = snd_pcm_hw_refine(pcm, params);
1571 if (err < 0)
1572 return err;
1573 }
1574 return snd_pcm_hw_param_value(params, var, NULL);
1575}
1576
1577int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params,
1578 snd_pcm_hw_param_t var, const snd_mask_t *val)
1579{
1580 int changed;
1581 assert(hw_is_mask(var));
1582 changed = snd_mask_refine(hw_param_mask(params, var), val);
1583 if (changed) {
1584 params->cmask |= 1 << var;
1585 params->rmask |= 1 << var;
1586 }
1587 return changed;
1588}
1589
1590/**
1591 * snd_pcm_hw_param_mask
1592 *
1593 * Inside configuration space defined by PARAMS remove from PAR all values
1594 * not contained in MASK. Reduce configuration space accordingly.
1595 * This function can be called only for SNDRV_PCM_HW_PARAM_ACCESS,
1596 * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
1597 * Return 0 on success or -EINVAL
1598 * if the configuration space is empty
1599 */
1600int snd_pcm_hw_param_mask(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1601 snd_pcm_hw_param_t var, const snd_mask_t *val)
1602{
1603 int changed = _snd_pcm_hw_param_mask(params, var, val);
1604 if (changed < 0)
1605 return changed;
1606 if (params->rmask) {
1607 int err = snd_pcm_hw_refine(pcm, params);
1608 if (err < 0)
1609 return err;
1610 }
1611 return 0;
1612}
1613
1614static int boundary_sub(int a, int adir,
1615 int b, int bdir,
1616 int *c, int *cdir)
1617{
1618 adir = adir < 0 ? -1 : (adir > 0 ? 1 : 0);
1619 bdir = bdir < 0 ? -1 : (bdir > 0 ? 1 : 0);
1620 *c = a - b;
1621 *cdir = adir - bdir;
1622 if (*cdir == -2) {
1623 assert(*c > INT_MIN);
1624 (*c)--;
1625 } else if (*cdir == 2) {
1626 assert(*c < INT_MAX);
1627 (*c)++;
1628 }
1629 return 0;
1630}
1631
1632static int boundary_lt(unsigned int a, int adir,
1633 unsigned int b, int bdir)
1634{
1635 assert(a > 0 || adir >= 0);
1636 assert(b > 0 || bdir >= 0);
1637 if (adir < 0) {
1638 a--;
1639 adir = 1;
1640 } else if (adir > 0)
1641 adir = 1;
1642 if (bdir < 0) {
1643 b--;
1644 bdir = 1;
1645 } else if (bdir > 0)
1646 bdir = 1;
1647 return a < b || (a == b && adir < bdir);
1648}
1649
1650/* Return 1 if min is nearer to best than max */
1651static int boundary_nearer(int min, int mindir,
1652 int best, int bestdir,
1653 int max, int maxdir)
1654{
1655 int dmin, dmindir;
1656 int dmax, dmaxdir;
1657 boundary_sub(best, bestdir, min, mindir, &dmin, &dmindir);
1658 boundary_sub(max, maxdir, best, bestdir, &dmax, &dmaxdir);
1659 return boundary_lt(dmin, dmindir, dmax, dmaxdir);
1660}
1661
1662/**
1663 * snd_pcm_hw_param_near
1664 *
1665 * Inside configuration space defined by PARAMS set PAR to the available value
1666 * nearest to VAL. Reduce configuration space accordingly.
1667 * This function cannot be called for SNDRV_PCM_HW_PARAM_ACCESS,
1668 * SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_SUBFORMAT.
1669 * Return the value found.
1670 */
1671int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
1672 snd_pcm_hw_param_t var, unsigned int best, int *dir)
1673{
1674 snd_pcm_hw_params_t *save = NULL;
1675 int v;
1676 unsigned int saved_min;
1677 int last = 0;
1678 int min, max;
1679 int mindir, maxdir;
1680 int valdir = dir ? *dir : 0;
1681 /* FIXME */
1682 if (best > INT_MAX)
1683 best = INT_MAX;
1684 min = max = best;
1685 mindir = maxdir = valdir;
1686 if (maxdir > 0)
1687 maxdir = 0;
1688 else if (maxdir == 0)
1689 maxdir = -1;
1690 else {
1691 maxdir = 1;
1692 max--;
1693 }
1694 save = kmalloc(sizeof(*save), GFP_KERNEL);
1695 if (save == NULL)
1696 return -ENOMEM;
1697 *save = *params;
1698 saved_min = min;
1699 min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
1700 if (min >= 0) {
1701 snd_pcm_hw_params_t *params1;
1702 if (max < 0)
1703 goto _end;
1704 if ((unsigned int)min == saved_min && mindir == valdir)
1705 goto _end;
1706 params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
1707 if (params1 == NULL) {
1708 kfree(save);
1709 return -ENOMEM;
1710 }
1711 *params1 = *save;
1712 max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
1713 if (max < 0) {
1714 kfree(params1);
1715 goto _end;
1716 }
1717 if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
1718 *params = *params1;
1719 last = 1;
1720 }
1721 kfree(params1);
1722 } else {
1723 *params = *save;
1724 max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
1725 assert(max >= 0);
1726 last = 1;
1727 }
1728 _end:
1729 kfree(save);
1730 if (last)
1731 v = snd_pcm_hw_param_last(pcm, params, var, dir);
1732 else
1733 v = snd_pcm_hw_param_first(pcm, params, var, dir);
1734 assert(v >= 0);
1735 return v;
1736}
1737
1738/**
1739 * snd_pcm_hw_param_choose
1740 *
1741 * Choose one configuration from configuration space defined by PARAMS
1742 * The configuration chosen is that obtained fixing in this order:
1743 * first access, first format, first subformat, min channels,
1744 * min rate, min period time, max buffer size, min tick time
1745 */
1746int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
1747{
1748 int err;
1749
1750 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_ACCESS, NULL);
1751 assert(err >= 0);
1752
1753 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_FORMAT, NULL);
1754 assert(err >= 0);
1755
1756 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_SUBFORMAT, NULL);
1757 assert(err >= 0);
1758
1759 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_CHANNELS, NULL);
1760 assert(err >= 0);
1761
1762 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_RATE, NULL);
1763 assert(err >= 0);
1764
1765 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_PERIOD_TIME, NULL);
1766 assert(err >= 0);
1767
1768 err = snd_pcm_hw_param_last(pcm, params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL);
1769 assert(err >= 0);
1770
1771 err = snd_pcm_hw_param_first(pcm, params, SNDRV_PCM_HW_PARAM_TICK_TIME, NULL);
1772 assert(err >= 0);
1773
1774 return 0;
1775}
1776
1777#undef snd_pcm_t
1778#undef assert
1779
1780static int snd_pcm_lib_ioctl_reset(snd_pcm_substream_t *substream,
1781 void *arg)
1782{
1783 snd_pcm_runtime_t *runtime = substream->runtime;
1784 unsigned long flags;
1785 snd_pcm_stream_lock_irqsave(substream, flags);
1786 if (snd_pcm_running(substream) &&
1787 snd_pcm_update_hw_ptr(substream) >= 0)
1788 runtime->status->hw_ptr %= runtime->buffer_size;
1789 else
1790 runtime->status->hw_ptr = 0;
1791 snd_pcm_stream_unlock_irqrestore(substream, flags);
1792 return 0;
1793}
1794
1795static int snd_pcm_lib_ioctl_channel_info(snd_pcm_substream_t *substream,
1796 void *arg)
1797{
1798 snd_pcm_channel_info_t *info = arg;
1799 snd_pcm_runtime_t *runtime = substream->runtime;
1800 int width;
1801 if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {
1802 info->offset = -1;
1803 return 0;
1804 }
1805 width = snd_pcm_format_physical_width(runtime->format);
1806 if (width < 0)
1807 return width;
1808 info->offset = 0;
1809 switch (runtime->access) {
1810 case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
1811 case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
1812 info->first = info->channel * width;
1813 info->step = runtime->channels * width;
1814 break;
1815 case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:
1816 case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
1817 {
1818 size_t size = runtime->dma_bytes / runtime->channels;
1819 info->first = info->channel * size * 8;
1820 info->step = width;
1821 break;
1822 }
1823 default:
1824 snd_BUG();
1825 break;
1826 }
1827 return 0;
1828}
1829
1830/**
1831 * snd_pcm_lib_ioctl - a generic PCM ioctl callback
1832 * @substream: the pcm substream instance
1833 * @cmd: ioctl command
1834 * @arg: ioctl argument
1835 *
1836 * Processes the generic ioctl commands for PCM.
1837 * Can be passed as the ioctl callback for PCM ops.
1838 *
1839 * Returns zero if successful, or a negative error code on failure.
1840 */
1841int snd_pcm_lib_ioctl(snd_pcm_substream_t *substream,
1842 unsigned int cmd, void *arg)
1843{
1844 switch (cmd) {
1845 case SNDRV_PCM_IOCTL1_INFO:
1846 return 0;
1847 case SNDRV_PCM_IOCTL1_RESET:
1848 return snd_pcm_lib_ioctl_reset(substream, arg);
1849 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
1850 return snd_pcm_lib_ioctl_channel_info(substream, arg);
1851 }
1852 return -ENXIO;
1853}
1854
1855/*
1856 * Conditions
1857 */
1858
1859static void snd_pcm_system_tick_set(snd_pcm_substream_t *substream,
1860 unsigned long ticks)
1861{
1862 snd_pcm_runtime_t *runtime = substream->runtime;
1863 if (ticks == 0)
1864 del_timer(&runtime->tick_timer);
1865 else {
1866 ticks += (1000000 / HZ) - 1;
1867 ticks /= (1000000 / HZ);
1868 mod_timer(&runtime->tick_timer, jiffies + ticks);
1869 }
1870}
1871
1872/* Temporary alias */
1873void snd_pcm_tick_set(snd_pcm_substream_t *substream, unsigned long ticks)
1874{
1875 snd_pcm_system_tick_set(substream, ticks);
1876}
1877
1878void snd_pcm_tick_prepare(snd_pcm_substream_t *substream)
1879{
1880 snd_pcm_runtime_t *runtime = substream->runtime;
1881 snd_pcm_uframes_t frames = ULONG_MAX;
1882 snd_pcm_uframes_t avail, dist;
1883 unsigned int ticks;
1884 u_int64_t n;
1885 u_int32_t r;
1886 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1887 if (runtime->silence_size >= runtime->boundary) {
1888 frames = 1;
1889 } else if (runtime->silence_size > 0 &&
1890 runtime->silence_filled < runtime->buffer_size) {
1891 snd_pcm_sframes_t noise_dist;
1892 noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
1893 snd_assert(noise_dist <= (snd_pcm_sframes_t)runtime->silence_threshold, );
1894 frames = noise_dist - runtime->silence_threshold;
1895 }
1896 avail = snd_pcm_playback_avail(runtime);
1897 } else {
1898 avail = snd_pcm_capture_avail(runtime);
1899 }
1900 if (avail < runtime->control->avail_min) {
1901 snd_pcm_sframes_t n = runtime->control->avail_min - avail;
1902 if (n > 0 && frames > (snd_pcm_uframes_t)n)
1903 frames = n;
1904 }
1905 if (avail < runtime->buffer_size) {
1906 snd_pcm_sframes_t n = runtime->buffer_size - avail;
1907 if (n > 0 && frames > (snd_pcm_uframes_t)n)
1908 frames = n;
1909 }
1910 if (frames == ULONG_MAX) {
1911 snd_pcm_tick_set(substream, 0);
1912 return;
1913 }
1914 dist = runtime->status->hw_ptr - runtime->hw_ptr_base;
1915 /* Distance to next interrupt */
1916 dist = runtime->period_size - dist % runtime->period_size;
1917 if (dist <= frames) {
1918 snd_pcm_tick_set(substream, 0);
1919 return;
1920 }
1921 /* the base time is us */
1922 n = frames;
1923 n *= 1000000;
1924 div64_32(&n, runtime->tick_time * runtime->rate, &r);
1925 ticks = n + (r > 0 ? 1 : 0);
1926 if (ticks < runtime->sleep_min)
1927 ticks = runtime->sleep_min;
1928 snd_pcm_tick_set(substream, (unsigned long) ticks);
1929}
1930
1931void snd_pcm_tick_elapsed(snd_pcm_substream_t *substream)
1932{
1933 snd_pcm_runtime_t *runtime;
1934 unsigned long flags;
1935
1936 snd_assert(substream != NULL, return);
1937 runtime = substream->runtime;
1938 snd_assert(runtime != NULL, return);
1939
1940 snd_pcm_stream_lock_irqsave(substream, flags);
1941 if (!snd_pcm_running(substream) ||
1942 snd_pcm_update_hw_ptr(substream) < 0)
1943 goto _end;
1944 if (runtime->sleep_min)
1945 snd_pcm_tick_prepare(substream);
1946 _end:
1947 snd_pcm_stream_unlock_irqrestore(substream, flags);
1948}
1949
1950/**
1951 * snd_pcm_period_elapsed - update the pcm status for the next period
1952 * @substream: the pcm substream instance
1953 *
1954 * This function is called from the interrupt handler when the
1955 * PCM has processed the period size. It will update the current
1956 * pointer, set up the tick, wake up sleepers, etc.
1957 *
1958 * Even if more than one periods have elapsed since the last call, you
1959 * have to call this only once.
1960 */
1961void snd_pcm_period_elapsed(snd_pcm_substream_t *substream)
1962{
1963 snd_pcm_runtime_t *runtime;
1964 unsigned long flags;
1965
1966 snd_assert(substream != NULL, return);
1967 runtime = substream->runtime;
1968 snd_assert(runtime != NULL, return);
1969
1970 if (runtime->transfer_ack_begin)
1971 runtime->transfer_ack_begin(substream);
1972
1973 snd_pcm_stream_lock_irqsave(substream, flags);
1974 if (!snd_pcm_running(substream) ||
1975 snd_pcm_update_hw_ptr_interrupt(substream) < 0)
1976 goto _end;
1977
1978 if (substream->timer_running)
1979 snd_timer_interrupt(substream->timer, 1);
1980 if (runtime->sleep_min)
1981 snd_pcm_tick_prepare(substream);
1982 _end:
1983 snd_pcm_stream_unlock_irqrestore(substream, flags);
1984 if (runtime->transfer_ack_end)
1985 runtime->transfer_ack_end(substream);
1986 kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
1987}
1988
1989static int snd_pcm_lib_write_transfer(snd_pcm_substream_t *substream,
1990 unsigned int hwoff,
1991 unsigned long data, unsigned int off,
1992 snd_pcm_uframes_t frames)
1993{
1994 snd_pcm_runtime_t *runtime = substream->runtime;
1995 int err;
1996 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
1997 if (substream->ops->copy) {
1998 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
1999 return err;
2000 } else {
2001 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
2002 snd_assert(runtime->dma_area, return -EFAULT);
2003 if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
2004 return -EFAULT;
2005 }
2006 return 0;
2007}
2008
2009typedef int (*transfer_f)(snd_pcm_substream_t *substream, unsigned int hwoff,
2010 unsigned long data, unsigned int off,
2011 snd_pcm_uframes_t size);
2012
2013static snd_pcm_sframes_t snd_pcm_lib_write1(snd_pcm_substream_t *substream,
2014 unsigned long data,
2015 snd_pcm_uframes_t size,
2016 int nonblock,
2017 transfer_f transfer)
2018{
2019 snd_pcm_runtime_t *runtime = substream->runtime;
2020 snd_pcm_uframes_t xfer = 0;
2021 snd_pcm_uframes_t offset = 0;
2022 int err = 0;
2023
2024 if (size == 0)
2025 return 0;
2026 if (size > runtime->xfer_align)
2027 size -= size % runtime->xfer_align;
2028
2029 snd_pcm_stream_lock_irq(substream);
2030 switch (runtime->status->state) {
2031 case SNDRV_PCM_STATE_PREPARED:
2032 case SNDRV_PCM_STATE_RUNNING:
2033 case SNDRV_PCM_STATE_PAUSED:
2034 break;
2035 case SNDRV_PCM_STATE_XRUN:
2036 err = -EPIPE;
2037 goto _end_unlock;
2038 case SNDRV_PCM_STATE_SUSPENDED:
2039 err = -ESTRPIPE;
2040 goto _end_unlock;
2041 default:
2042 err = -EBADFD;
2043 goto _end_unlock;
2044 }
2045
2046 while (size > 0) {
2047 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2048 snd_pcm_uframes_t avail;
2049 snd_pcm_uframes_t cont;
2050 if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2051 snd_pcm_update_hw_ptr(substream);
2052 avail = snd_pcm_playback_avail(runtime);
2053 if (((avail < runtime->control->avail_min && size > avail) ||
2054 (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
2055 wait_queue_t wait;
2056 enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
2057 long tout;
2058
2059 if (nonblock) {
2060 err = -EAGAIN;
2061 goto _end_unlock;
2062 }
2063
2064 init_waitqueue_entry(&wait, current);
2065 add_wait_queue(&runtime->sleep, &wait);
2066 while (1) {
2067 if (signal_pending(current)) {
2068 state = SIGNALED;
2069 break;
2070 }
2071 set_current_state(TASK_INTERRUPTIBLE);
2072 snd_pcm_stream_unlock_irq(substream);
2073 tout = schedule_timeout(10 * HZ);
2074 snd_pcm_stream_lock_irq(substream);
2075 if (tout == 0) {
2076 if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
2077 runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
2078 state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
2079 break;
2080 }
2081 }
2082 switch (runtime->status->state) {
2083 case SNDRV_PCM_STATE_XRUN:
2084 case SNDRV_PCM_STATE_DRAINING:
2085 state = ERROR;
2086 goto _end_loop;
2087 case SNDRV_PCM_STATE_SUSPENDED:
2088 state = SUSPENDED;
2089 goto _end_loop;
2090 default:
2091 break;
2092 }
2093 avail = snd_pcm_playback_avail(runtime);
2094 if (avail >= runtime->control->avail_min) {
2095 state = READY;
2096 break;
2097 }
2098 }
2099 _end_loop:
2100 remove_wait_queue(&runtime->sleep, &wait);
2101
2102 switch (state) {
2103 case ERROR:
2104 err = -EPIPE;
2105 goto _end_unlock;
2106 case SUSPENDED:
2107 err = -ESTRPIPE;
2108 goto _end_unlock;
2109 case SIGNALED:
2110 err = -ERESTARTSYS;
2111 goto _end_unlock;
2112 case EXPIRED:
2113 snd_printd("playback write error (DMA or IRQ trouble?)\n");
2114 err = -EIO;
2115 goto _end_unlock;
2116 default:
2117 break;
2118 }
2119 }
2120 if (avail > runtime->xfer_align)
2121 avail -= avail % runtime->xfer_align;
2122 frames = size > avail ? avail : size;
2123 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
2124 if (frames > cont)
2125 frames = cont;
2126 snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
2127 appl_ptr = runtime->control->appl_ptr;
2128 appl_ofs = appl_ptr % runtime->buffer_size;
2129 snd_pcm_stream_unlock_irq(substream);
2130 if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
2131 goto _end;
2132 snd_pcm_stream_lock_irq(substream);
2133 switch (runtime->status->state) {
2134 case SNDRV_PCM_STATE_XRUN:
2135 err = -EPIPE;
2136 goto _end_unlock;
2137 case SNDRV_PCM_STATE_SUSPENDED:
2138 err = -ESTRPIPE;
2139 goto _end_unlock;
2140 default:
2141 break;
2142 }
2143 appl_ptr += frames;
2144 if (appl_ptr >= runtime->boundary)
2145 appl_ptr -= runtime->boundary;
2146 runtime->control->appl_ptr = appl_ptr;
2147 if (substream->ops->ack)
2148 substream->ops->ack(substream);
2149
2150 offset += frames;
2151 size -= frames;
2152 xfer += frames;
2153 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
2154 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
2155 err = snd_pcm_start(substream);
2156 if (err < 0)
2157 goto _end_unlock;
2158 }
2159 if (runtime->sleep_min &&
2160 runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2161 snd_pcm_tick_prepare(substream);
2162 }
2163 _end_unlock:
2164 snd_pcm_stream_unlock_irq(substream);
2165 _end:
2166 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
2167}
2168
2169snd_pcm_sframes_t snd_pcm_lib_write(snd_pcm_substream_t *substream, const void __user *buf, snd_pcm_uframes_t size)
2170{
2171 snd_pcm_runtime_t *runtime;
2172 int nonblock;
2173
2174 snd_assert(substream != NULL, return -ENXIO);
2175 runtime = substream->runtime;
2176 snd_assert(runtime != NULL, return -ENXIO);
2177 snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
2178 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2179 return -EBADFD;
2180
2181 snd_assert(substream->ffile != NULL, return -ENXIO);
2182 nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
2183#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
2184 if (substream->oss.oss) {
2185 snd_pcm_oss_setup_t *setup = substream->oss.setup;
2186 if (setup != NULL) {
2187 if (setup->nonblock)
2188 nonblock = 1;
2189 else if (setup->block)
2190 nonblock = 0;
2191 }
2192 }
2193#endif
2194
2195 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
2196 runtime->channels > 1)
2197 return -EINVAL;
2198 return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
2199 snd_pcm_lib_write_transfer);
2200}
2201
2202static int snd_pcm_lib_writev_transfer(snd_pcm_substream_t *substream,
2203 unsigned int hwoff,
2204 unsigned long data, unsigned int off,
2205 snd_pcm_uframes_t frames)
2206{
2207 snd_pcm_runtime_t *runtime = substream->runtime;
2208 int err;
2209 void __user **bufs = (void __user **)data;
2210 int channels = runtime->channels;
2211 int c;
2212 if (substream->ops->copy) {
2213 snd_assert(substream->ops->silence != NULL, return -EINVAL);
2214 for (c = 0; c < channels; ++c, ++bufs) {
2215 if (*bufs == NULL) {
2216 if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
2217 return err;
2218 } else {
2219 char __user *buf = *bufs + samples_to_bytes(runtime, off);
2220 if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
2221 return err;
2222 }
2223 }
2224 } else {
2225 /* default transfer behaviour */
2226 size_t dma_csize = runtime->dma_bytes / channels;
2227 snd_assert(runtime->dma_area, return -EFAULT);
2228 for (c = 0; c < channels; ++c, ++bufs) {
2229 char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
2230 if (*bufs == NULL) {
2231 snd_pcm_format_set_silence(runtime->format, hwbuf, frames);
2232 } else {
2233 char __user *buf = *bufs + samples_to_bytes(runtime, off);
2234 if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames)))
2235 return -EFAULT;
2236 }
2237 }
2238 }
2239 return 0;
2240}
2241
2242snd_pcm_sframes_t snd_pcm_lib_writev(snd_pcm_substream_t *substream,
2243 void __user **bufs,
2244 snd_pcm_uframes_t frames)
2245{
2246 snd_pcm_runtime_t *runtime;
2247 int nonblock;
2248
2249 snd_assert(substream != NULL, return -ENXIO);
2250 runtime = substream->runtime;
2251 snd_assert(runtime != NULL, return -ENXIO);
2252 snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
2253 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2254 return -EBADFD;
2255
2256 snd_assert(substream->ffile != NULL, return -ENXIO);
2257 nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
2258#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
2259 if (substream->oss.oss) {
2260 snd_pcm_oss_setup_t *setup = substream->oss.setup;
2261 if (setup != NULL) {
2262 if (setup->nonblock)
2263 nonblock = 1;
2264 else if (setup->block)
2265 nonblock = 0;
2266 }
2267 }
2268#endif
2269
2270 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2271 return -EINVAL;
2272 return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames,
2273 nonblock, snd_pcm_lib_writev_transfer);
2274}
2275
2276static int snd_pcm_lib_read_transfer(snd_pcm_substream_t *substream,
2277 unsigned int hwoff,
2278 unsigned long data, unsigned int off,
2279 snd_pcm_uframes_t frames)
2280{
2281 snd_pcm_runtime_t *runtime = substream->runtime;
2282 int err;
2283 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
2284 if (substream->ops->copy) {
2285 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
2286 return err;
2287 } else {
2288 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
2289 snd_assert(runtime->dma_area, return -EFAULT);
2290 if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
2291 return -EFAULT;
2292 }
2293 return 0;
2294}
2295
2296static snd_pcm_sframes_t snd_pcm_lib_read1(snd_pcm_substream_t *substream,
2297 unsigned long data,
2298 snd_pcm_uframes_t size,
2299 int nonblock,
2300 transfer_f transfer)
2301{
2302 snd_pcm_runtime_t *runtime = substream->runtime;
2303 snd_pcm_uframes_t xfer = 0;
2304 snd_pcm_uframes_t offset = 0;
2305 int err = 0;
2306
2307 if (size == 0)
2308 return 0;
2309 if (size > runtime->xfer_align)
2310 size -= size % runtime->xfer_align;
2311
2312 snd_pcm_stream_lock_irq(substream);
2313 switch (runtime->status->state) {
2314 case SNDRV_PCM_STATE_PREPARED:
2315 if (size >= runtime->start_threshold) {
2316 err = snd_pcm_start(substream);
2317 if (err < 0)
2318 goto _end_unlock;
2319 }
2320 break;
2321 case SNDRV_PCM_STATE_DRAINING:
2322 case SNDRV_PCM_STATE_RUNNING:
2323 case SNDRV_PCM_STATE_PAUSED:
2324 break;
2325 case SNDRV_PCM_STATE_XRUN:
2326 err = -EPIPE;
2327 goto _end_unlock;
2328 case SNDRV_PCM_STATE_SUSPENDED:
2329 err = -ESTRPIPE;
2330 goto _end_unlock;
2331 default:
2332 err = -EBADFD;
2333 goto _end_unlock;
2334 }
2335
2336 while (size > 0) {
2337 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2338 snd_pcm_uframes_t avail;
2339 snd_pcm_uframes_t cont;
2340 if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2341 snd_pcm_update_hw_ptr(substream);
2342 __draining:
2343 avail = snd_pcm_capture_avail(runtime);
2344 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
2345 if (avail < runtime->xfer_align) {
2346 err = -EPIPE;
2347 goto _end_unlock;
2348 }
2349 } else if ((avail < runtime->control->avail_min && size > avail) ||
2350 (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
2351 wait_queue_t wait;
2352 enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
2353 long tout;
2354
2355 if (nonblock) {
2356 err = -EAGAIN;
2357 goto _end_unlock;
2358 }
2359
2360 init_waitqueue_entry(&wait, current);
2361 add_wait_queue(&runtime->sleep, &wait);
2362 while (1) {
2363 if (signal_pending(current)) {
2364 state = SIGNALED;
2365 break;
2366 }
2367 set_current_state(TASK_INTERRUPTIBLE);
2368 snd_pcm_stream_unlock_irq(substream);
2369 tout = schedule_timeout(10 * HZ);
2370 snd_pcm_stream_lock_irq(substream);
2371 if (tout == 0) {
2372 if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
2373 runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
2374 state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
2375 break;
2376 }
2377 }
2378 switch (runtime->status->state) {
2379 case SNDRV_PCM_STATE_XRUN:
2380 state = ERROR;
2381 goto _end_loop;
2382 case SNDRV_PCM_STATE_SUSPENDED:
2383 state = SUSPENDED;
2384 goto _end_loop;
2385 case SNDRV_PCM_STATE_DRAINING:
2386 goto __draining;
2387 default:
2388 break;
2389 }
2390 avail = snd_pcm_capture_avail(runtime);
2391 if (avail >= runtime->control->avail_min) {
2392 state = READY;
2393 break;
2394 }
2395 }
2396 _end_loop:
2397 remove_wait_queue(&runtime->sleep, &wait);
2398
2399 switch (state) {
2400 case ERROR:
2401 err = -EPIPE;
2402 goto _end_unlock;
2403 case SUSPENDED:
2404 err = -ESTRPIPE;
2405 goto _end_unlock;
2406 case SIGNALED:
2407 err = -ERESTARTSYS;
2408 goto _end_unlock;
2409 case EXPIRED:
2410 snd_printd("capture read error (DMA or IRQ trouble?)\n");
2411 err = -EIO;
2412 goto _end_unlock;
2413 default:
2414 break;
2415 }
2416 }
2417 if (avail > runtime->xfer_align)
2418 avail -= avail % runtime->xfer_align;
2419 frames = size > avail ? avail : size;
2420 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
2421 if (frames > cont)
2422 frames = cont;
2423 snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL);
2424 appl_ptr = runtime->control->appl_ptr;
2425 appl_ofs = appl_ptr % runtime->buffer_size;
2426 snd_pcm_stream_unlock_irq(substream);
2427 if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
2428 goto _end;
2429 snd_pcm_stream_lock_irq(substream);
2430 switch (runtime->status->state) {
2431 case SNDRV_PCM_STATE_XRUN:
2432 err = -EPIPE;
2433 goto _end_unlock;
2434 case SNDRV_PCM_STATE_SUSPENDED:
2435 err = -ESTRPIPE;
2436 goto _end_unlock;
2437 default:
2438 break;
2439 }
2440 appl_ptr += frames;
2441 if (appl_ptr >= runtime->boundary)
2442 appl_ptr -= runtime->boundary;
2443 runtime->control->appl_ptr = appl_ptr;
2444 if (substream->ops->ack)
2445 substream->ops->ack(substream);
2446
2447 offset += frames;
2448 size -= frames;
2449 xfer += frames;
2450 if (runtime->sleep_min &&
2451 runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2452 snd_pcm_tick_prepare(substream);
2453 }
2454 _end_unlock:
2455 snd_pcm_stream_unlock_irq(substream);
2456 _end:
2457 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
2458}
2459
2460snd_pcm_sframes_t snd_pcm_lib_read(snd_pcm_substream_t *substream, void __user *buf, snd_pcm_uframes_t size)
2461{
2462 snd_pcm_runtime_t *runtime;
2463 int nonblock;
2464
2465 snd_assert(substream != NULL, return -ENXIO);
2466 runtime = substream->runtime;
2467 snd_assert(runtime != NULL, return -ENXIO);
2468 snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
2469 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2470 return -EBADFD;
2471
2472 snd_assert(substream->ffile != NULL, return -ENXIO);
2473 nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
2474#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
2475 if (substream->oss.oss) {
2476 snd_pcm_oss_setup_t *setup = substream->oss.setup;
2477 if (setup != NULL) {
2478 if (setup->nonblock)
2479 nonblock = 1;
2480 else if (setup->block)
2481 nonblock = 0;
2482 }
2483 }
2484#endif
2485 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
2486 return -EINVAL;
2487 return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
2488}
2489
2490static int snd_pcm_lib_readv_transfer(snd_pcm_substream_t *substream,
2491 unsigned int hwoff,
2492 unsigned long data, unsigned int off,
2493 snd_pcm_uframes_t frames)
2494{
2495 snd_pcm_runtime_t *runtime = substream->runtime;
2496 int err;
2497 void __user **bufs = (void __user **)data;
2498 int channels = runtime->channels;
2499 int c;
2500 if (substream->ops->copy) {
2501 for (c = 0; c < channels; ++c, ++bufs) {
2502 char __user *buf;
2503 if (*bufs == NULL)
2504 continue;
2505 buf = *bufs + samples_to_bytes(runtime, off);
2506 if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
2507 return err;
2508 }
2509 } else {
2510 snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
2511 snd_assert(runtime->dma_area, return -EFAULT);
2512 for (c = 0; c < channels; ++c, ++bufs) {
2513 char *hwbuf;
2514 char __user *buf;
2515 if (*bufs == NULL)
2516 continue;
2517
2518 hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
2519 buf = *bufs + samples_to_bytes(runtime, off);
2520 if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames)))
2521 return -EFAULT;
2522 }
2523 }
2524 return 0;
2525}
2526
2527snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream,
2528 void __user **bufs,
2529 snd_pcm_uframes_t frames)
2530{
2531 snd_pcm_runtime_t *runtime;
2532 int nonblock;
2533
2534 snd_assert(substream != NULL, return -ENXIO);
2535 runtime = substream->runtime;
2536 snd_assert(runtime != NULL, return -ENXIO);
2537 snd_assert(substream->ops->copy != NULL || runtime->dma_area != NULL, return -EINVAL);
2538 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2539 return -EBADFD;
2540
2541 snd_assert(substream->ffile != NULL, return -ENXIO);
2542 nonblock = !!(substream->ffile->f_flags & O_NONBLOCK);
2543#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
2544 if (substream->oss.oss) {
2545 snd_pcm_oss_setup_t *setup = substream->oss.setup;
2546 if (setup != NULL) {
2547 if (setup->nonblock)
2548 nonblock = 1;
2549 else if (setup->block)
2550 nonblock = 0;
2551 }
2552 }
2553#endif
2554
2555 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2556 return -EINVAL;
2557 return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
2558}
2559
2560/*
2561 * Exported symbols
2562 */
2563
2564EXPORT_SYMBOL(snd_interval_refine);
2565EXPORT_SYMBOL(snd_interval_list);
2566EXPORT_SYMBOL(snd_interval_ratnum);
2567EXPORT_SYMBOL(snd_interval_muldivk);
2568EXPORT_SYMBOL(snd_interval_mulkdiv);
2569EXPORT_SYMBOL(snd_interval_div);
2570EXPORT_SYMBOL(_snd_pcm_hw_params_any);
2571EXPORT_SYMBOL(_snd_pcm_hw_param_min);
2572EXPORT_SYMBOL(_snd_pcm_hw_param_set);
2573EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
2574EXPORT_SYMBOL(_snd_pcm_hw_param_setinteger);
2575EXPORT_SYMBOL(snd_pcm_hw_param_value_min);
2576EXPORT_SYMBOL(snd_pcm_hw_param_value_max);
2577EXPORT_SYMBOL(snd_pcm_hw_param_mask);
2578EXPORT_SYMBOL(snd_pcm_hw_param_first);
2579EXPORT_SYMBOL(snd_pcm_hw_param_last);
2580EXPORT_SYMBOL(snd_pcm_hw_param_near);
2581EXPORT_SYMBOL(snd_pcm_hw_param_set);
2582EXPORT_SYMBOL(snd_pcm_hw_refine);
2583EXPORT_SYMBOL(snd_pcm_hw_params);
2584EXPORT_SYMBOL(snd_pcm_hw_constraints_init);
2585EXPORT_SYMBOL(snd_pcm_hw_constraints_complete);
2586EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
2587EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
2588EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
2589EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
2590EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
2591EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
2592EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
2593EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
2594EXPORT_SYMBOL(snd_pcm_hw_rule_add);
2595EXPORT_SYMBOL(snd_pcm_set_ops);
2596EXPORT_SYMBOL(snd_pcm_set_sync);
2597EXPORT_SYMBOL(snd_pcm_lib_ioctl);
2598EXPORT_SYMBOL(snd_pcm_stop);
2599EXPORT_SYMBOL(snd_pcm_period_elapsed);
2600EXPORT_SYMBOL(snd_pcm_lib_write);
2601EXPORT_SYMBOL(snd_pcm_lib_read);
2602EXPORT_SYMBOL(snd_pcm_lib_writev);
2603EXPORT_SYMBOL(snd_pcm_lib_readv);
2604EXPORT_SYMBOL(snd_pcm_lib_buffer_bytes);
2605EXPORT_SYMBOL(snd_pcm_lib_period_bytes);
2606/* pcm_memory.c */
2607EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all);
2608EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages);
2609EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all);
2610EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page);
2611EXPORT_SYMBOL(snd_pcm_lib_malloc_pages);
2612EXPORT_SYMBOL(snd_pcm_lib_free_pages);
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
new file mode 100644
index 000000000000..f1d5f7a6ee0c
--- /dev/null
+++ b/sound/core/pcm_memory.c
@@ -0,0 +1,363 @@
1/*
2 * Digital Audio (PCM) abstract layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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 <asm/io.h>
24#include <linux/time.h>
25#include <linux/init.h>
26#include <linux/moduleparam.h>
27#include <sound/core.h>
28#include <sound/pcm.h>
29#include <sound/info.h>
30#include <sound/initval.h>
31
32static int preallocate_dma = 1;
33module_param(preallocate_dma, int, 0444);
34MODULE_PARM_DESC(preallocate_dma, "Preallocate DMA memory when the PCM devices are initialized.");
35
36static int maximum_substreams = 4;
37module_param(maximum_substreams, int, 0444);
38MODULE_PARM_DESC(maximum_substreams, "Maximum substreams with preallocated DMA memory.");
39
40static const size_t snd_minimum_buffer = 16384;
41
42
43/*
44 * try to allocate as the large pages as possible.
45 * stores the resultant memory size in *res_size.
46 *
47 * the minimum size is snd_minimum_buffer. it should be power of 2.
48 */
49static int preallocate_pcm_pages(snd_pcm_substream_t *substream, size_t size)
50{
51 struct snd_dma_buffer *dmab = &substream->dma_buffer;
52 int err;
53
54 snd_assert(size > 0, return -EINVAL);
55
56 /* already reserved? */
57 if (snd_dma_get_reserved_buf(dmab, substream->dma_buf_id) > 0) {
58 if (dmab->bytes >= size)
59 return 0; /* yes */
60 /* no, free the reserved block */
61 snd_dma_free_pages(dmab);
62 dmab->bytes = 0;
63 }
64
65 do {
66 if ((err = snd_dma_alloc_pages(dmab->dev.type, dmab->dev.dev,
67 size, dmab)) < 0) {
68 if (err != -ENOMEM)
69 return err; /* fatal error */
70 } else
71 return 0;
72 size >>= 1;
73 } while (size >= snd_minimum_buffer);
74 dmab->bytes = 0; /* tell error */
75 return 0;
76}
77
78/*
79 * release the preallocated buffer if not yet done.
80 */
81static void snd_pcm_lib_preallocate_dma_free(snd_pcm_substream_t *substream)
82{
83 if (substream->dma_buffer.area == NULL)
84 return;
85 if (substream->dma_buf_id)
86 snd_dma_reserve_buf(&substream->dma_buffer, substream->dma_buf_id);
87 else
88 snd_dma_free_pages(&substream->dma_buffer);
89 substream->dma_buffer.area = NULL;
90}
91
92/**
93 * snd_pcm_lib_preallocate_free - release the preallocated buffer of the specified substream.
94 * @substream: the pcm substream instance
95 *
96 * Releases the pre-allocated buffer of the given substream.
97 *
98 * Returns zero if successful, or a negative error code on failure.
99 */
100int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream)
101{
102 snd_pcm_lib_preallocate_dma_free(substream);
103 if (substream->proc_prealloc_entry) {
104 snd_info_unregister(substream->proc_prealloc_entry);
105 substream->proc_prealloc_entry = NULL;
106 }
107 return 0;
108}
109
110/**
111 * snd_pcm_lib_preallocate_free_for_all - release all pre-allocated buffers on the pcm
112 * @pcm: the pcm instance
113 *
114 * Releases all the pre-allocated buffers on the given pcm.
115 *
116 * Returns zero if successful, or a negative error code on failure.
117 */
118int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm)
119{
120 snd_pcm_substream_t *substream;
121 int stream;
122
123 for (stream = 0; stream < 2; stream++)
124 for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
125 snd_pcm_lib_preallocate_free(substream);
126 return 0;
127}
128
129/*
130 * read callback for prealloc proc file
131 *
132 * prints the current allocated size in kB.
133 */
134static void snd_pcm_lib_preallocate_proc_read(snd_info_entry_t *entry,
135 snd_info_buffer_t *buffer)
136{
137 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
138 snd_iprintf(buffer, "%lu\n", (unsigned long) substream->dma_buffer.bytes / 1024);
139}
140
141/*
142 * write callback for prealloc proc file
143 *
144 * accepts the preallocation size in kB.
145 */
146static void snd_pcm_lib_preallocate_proc_write(snd_info_entry_t *entry,
147 snd_info_buffer_t *buffer)
148{
149 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)entry->private_data;
150 char line[64], str[64];
151 size_t size;
152 struct snd_dma_buffer new_dmab;
153
154 if (substream->runtime) {
155 buffer->error = -EBUSY;
156 return;
157 }
158 if (!snd_info_get_line(buffer, line, sizeof(line))) {
159 snd_info_get_str(str, line, sizeof(str));
160 size = simple_strtoul(str, NULL, 10) * 1024;
161 if ((size != 0 && size < 8192) || size > substream->dma_max) {
162 buffer->error = -EINVAL;
163 return;
164 }
165 if (substream->dma_buffer.bytes == size)
166 return;
167 memset(&new_dmab, 0, sizeof(new_dmab));
168 new_dmab.dev = substream->dma_buffer.dev;
169 if (size > 0) {
170 if (snd_dma_alloc_pages(substream->dma_buffer.dev.type,
171 substream->dma_buffer.dev.dev,
172 size, &new_dmab) < 0) {
173 buffer->error = -ENOMEM;
174 return;
175 }
176 substream->buffer_bytes_max = size;
177 } else {
178 substream->buffer_bytes_max = UINT_MAX;
179 }
180 if (substream->dma_buffer.area)
181 snd_dma_free_pages(&substream->dma_buffer);
182 substream->dma_buffer = new_dmab;
183 } else {
184 buffer->error = -EINVAL;
185 }
186}
187
188/*
189 * pre-allocate the buffer and create a proc file for the substream
190 */
191static int snd_pcm_lib_preallocate_pages1(snd_pcm_substream_t *substream,
192 size_t size, size_t max)
193{
194 snd_info_entry_t *entry;
195
196 if (size > 0 && preallocate_dma && substream->number < maximum_substreams)
197 preallocate_pcm_pages(substream, size);
198
199 if (substream->dma_buffer.bytes > 0)
200 substream->buffer_bytes_max = substream->dma_buffer.bytes;
201 substream->dma_max = max;
202 if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) {
203 entry->c.text.read_size = 64;
204 entry->c.text.read = snd_pcm_lib_preallocate_proc_read;
205 entry->c.text.write_size = 64;
206 entry->c.text.write = snd_pcm_lib_preallocate_proc_write;
207 entry->private_data = substream;
208 if (snd_info_register(entry) < 0) {
209 snd_info_free_entry(entry);
210 entry = NULL;
211 }
212 }
213 substream->proc_prealloc_entry = entry;
214 return 0;
215}
216
217
218/**
219 * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type
220 * @substream: the pcm substream instance
221 * @type: DMA type (SNDRV_DMA_TYPE_*)
222 * @data: DMA type dependant data
223 * @size: the requested pre-allocation size in bytes
224 * @max: the max. allowed pre-allocation size
225 *
226 * Do pre-allocation for the given DMA buffer type.
227 *
228 * When substream->dma_buf_id is set, the function tries to look for
229 * the reserved buffer, and the buffer is not freed but reserved at
230 * destruction time. The dma_buf_id must be unique for all systems
231 * (in the same DMA buffer type) e.g. using snd_dma_pci_buf_id().
232 *
233 * Returns zero if successful, or a negative error code on failure.
234 */
235int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream,
236 int type, struct device *data,
237 size_t size, size_t max)
238{
239 substream->dma_buffer.dev.type = type;
240 substream->dma_buffer.dev.dev = data;
241 return snd_pcm_lib_preallocate_pages1(substream, size, max);
242}
243
244/**
245 * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams)
246 * @substream: the pcm substream instance
247 * @type: DMA type (SNDRV_DMA_TYPE_*)
248 * @data: DMA type dependant data
249 * @size: the requested pre-allocation size in bytes
250 * @max: the max. allowed pre-allocation size
251 *
252 * Do pre-allocation to all substreams of the given pcm for the
253 * specified DMA type.
254 *
255 * Returns zero if successful, or a negative error code on failure.
256 */
257int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm,
258 int type, void *data,
259 size_t size, size_t max)
260{
261 snd_pcm_substream_t *substream;
262 int stream, err;
263
264 for (stream = 0; stream < 2; stream++)
265 for (substream = pcm->streams[stream].substream; substream; substream = substream->next)
266 if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0)
267 return err;
268 return 0;
269}
270
271/**
272 * snd_pcm_sgbuf_ops_page - get the page struct at the given offset
273 * @substream: the pcm substream instance
274 * @offset: the buffer offset
275 *
276 * Returns the page struct at the given buffer offset.
277 * Used as the page callback of PCM ops.
278 */
279struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
280{
281 struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
282
283 unsigned int idx = offset >> PAGE_SHIFT;
284 if (idx >= (unsigned int)sgbuf->pages)
285 return NULL;
286 return sgbuf->page_table[idx];
287}
288
289/**
290 * snd_pcm_lib_malloc_pages - allocate the DMA buffer
291 * @substream: the substream to allocate the DMA buffer to
292 * @size: the requested buffer size in bytes
293 *
294 * Allocates the DMA buffer on the BUS type given earlier to
295 * snd_pcm_lib_preallocate_xxx_pages().
296 *
297 * Returns 1 if the buffer is changed, 0 if not changed, or a negative
298 * code on failure.
299 */
300int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size)
301{
302 snd_pcm_runtime_t *runtime;
303 struct snd_dma_buffer *dmab = NULL;
304
305 snd_assert(substream->dma_buffer.dev.type != SNDRV_DMA_TYPE_UNKNOWN, return -EINVAL);
306 snd_assert(substream != NULL, return -EINVAL);
307 runtime = substream->runtime;
308 snd_assert(runtime != NULL, return -EINVAL);
309
310 if (runtime->dma_buffer_p) {
311 /* perphaps, we might free the large DMA memory region
312 to save some space here, but the actual solution
313 costs us less time */
314 if (runtime->dma_buffer_p->bytes >= size) {
315 runtime->dma_bytes = size;
316 return 0; /* ok, do not change */
317 }
318 snd_pcm_lib_free_pages(substream);
319 }
320 if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) {
321 dmab = &substream->dma_buffer; /* use the pre-allocated buffer */
322 } else {
323 dmab = kcalloc(1, sizeof(*dmab), GFP_KERNEL);
324 if (! dmab)
325 return -ENOMEM;
326 dmab->dev = substream->dma_buffer.dev;
327 if (snd_dma_alloc_pages(substream->dma_buffer.dev.type,
328 substream->dma_buffer.dev.dev,
329 size, dmab) < 0) {
330 kfree(dmab);
331 return -ENOMEM;
332 }
333 }
334 snd_pcm_set_runtime_buffer(substream, dmab);
335 runtime->dma_bytes = size;
336 return 1; /* area was changed */
337}
338
339/**
340 * snd_pcm_lib_free_pages - release the allocated DMA buffer.
341 * @substream: the substream to release the DMA buffer
342 *
343 * Releases the DMA buffer allocated via snd_pcm_lib_malloc_pages().
344 *
345 * Returns zero if successful, or a negative error code on failure.
346 */
347int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream)
348{
349 snd_pcm_runtime_t *runtime;
350
351 snd_assert(substream != NULL, return -EINVAL);
352 runtime = substream->runtime;
353 snd_assert(runtime != NULL, return -EINVAL);
354 if (runtime->dma_area == NULL)
355 return 0;
356 if (runtime->dma_buffer_p != &substream->dma_buffer) {
357 /* it's a newly allocated buffer. release it now. */
358 snd_dma_free_pages(runtime->dma_buffer_p);
359 kfree(runtime->dma_buffer_p);
360 }
361 snd_pcm_set_runtime_buffer(substream, NULL);
362 return 0;
363}
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
new file mode 100644
index 000000000000..422b8db14154
--- /dev/null
+++ b/sound/core/pcm_misc.c
@@ -0,0 +1,481 @@
1/*
2 * PCM Interface - misc routines
3 * Copyright (c) 1998 by Jaroslav Kysela <perex@suse.cz>
4 *
5 *
6 * This library is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Library General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (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 Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; 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/time.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#define SND_PCM_FORMAT_UNKNOWN (-1)
27
28/* NOTE: "signed" prefix must be given below since the default char is
29 * unsigned on some architectures!
30 */
31struct pcm_format_data {
32 unsigned char width; /* bit width */
33 unsigned char phys; /* physical bit width */
34 signed char le; /* 0 = big-endian, 1 = little-endian, -1 = others */
35 signed char signd; /* 0 = unsigned, 1 = signed, -1 = others */
36 unsigned char silence[8]; /* silence data to fill */
37};
38
39static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
40 [SNDRV_PCM_FORMAT_S8] = {
41 .width = 8, .phys = 8, .le = -1, .signd = 1,
42 .silence = {},
43 },
44 [SNDRV_PCM_FORMAT_U8] = {
45 .width = 8, .phys = 8, .le = -1, .signd = 0,
46 .silence = { 0x80 },
47 },
48 [SNDRV_PCM_FORMAT_S16_LE] = {
49 .width = 16, .phys = 16, .le = 1, .signd = 1,
50 .silence = {},
51 },
52 [SNDRV_PCM_FORMAT_S16_BE] = {
53 .width = 16, .phys = 16, .le = 0, .signd = 1,
54 .silence = {},
55 },
56 [SNDRV_PCM_FORMAT_U16_LE] = {
57 .width = 16, .phys = 16, .le = 1, .signd = 0,
58 .silence = { 0x00, 0x80 },
59 },
60 [SNDRV_PCM_FORMAT_U16_BE] = {
61 .width = 16, .phys = 16, .le = 0, .signd = 0,
62 .silence = { 0x80, 0x00 },
63 },
64 [SNDRV_PCM_FORMAT_S24_LE] = {
65 .width = 24, .phys = 32, .le = 1, .signd = 1,
66 .silence = {},
67 },
68 [SNDRV_PCM_FORMAT_S24_BE] = {
69 .width = 24, .phys = 32, .le = 0, .signd = 1,
70 .silence = {},
71 },
72 [SNDRV_PCM_FORMAT_U24_LE] = {
73 .width = 24, .phys = 32, .le = 1, .signd = 0,
74 .silence = { 0x00, 0x00, 0x80 },
75 },
76 [SNDRV_PCM_FORMAT_U24_BE] = {
77 .width = 24, .phys = 32, .le = 0, .signd = 0,
78 .silence = { 0x80, 0x00, 0x00 },
79 },
80 [SNDRV_PCM_FORMAT_S32_LE] = {
81 .width = 32, .phys = 32, .le = 1, .signd = 1,
82 .silence = {},
83 },
84 [SNDRV_PCM_FORMAT_S32_BE] = {
85 .width = 32, .phys = 32, .le = 0, .signd = 1,
86 .silence = {},
87 },
88 [SNDRV_PCM_FORMAT_U32_LE] = {
89 .width = 32, .phys = 32, .le = 1, .signd = 0,
90 .silence = { 0x00, 0x00, 0x00, 0x80 },
91 },
92 [SNDRV_PCM_FORMAT_U32_BE] = {
93 .width = 32, .phys = 32, .le = 0, .signd = 0,
94 .silence = { 0x80, 0x00, 0x00, 0x00 },
95 },
96 [SNDRV_PCM_FORMAT_FLOAT_LE] = {
97 .width = 32, .phys = 32, .le = 1, .signd = -1,
98 .silence = {},
99 },
100 [SNDRV_PCM_FORMAT_FLOAT_BE] = {
101 .width = 32, .phys = 32, .le = 0, .signd = -1,
102 .silence = {},
103 },
104 [SNDRV_PCM_FORMAT_FLOAT64_LE] = {
105 .width = 64, .phys = 64, .le = 1, .signd = -1,
106 .silence = {},
107 },
108 [SNDRV_PCM_FORMAT_FLOAT64_BE] = {
109 .width = 64, .phys = 64, .le = 0, .signd = -1,
110 .silence = {},
111 },
112 [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE] = {
113 .width = 32, .phys = 32, .le = 1, .signd = -1,
114 .silence = {},
115 },
116 [SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE] = {
117 .width = 32, .phys = 32, .le = 0, .signd = -1,
118 .silence = {},
119 },
120 [SNDRV_PCM_FORMAT_MU_LAW] = {
121 .width = 8, .phys = 8, .le = -1, .signd = -1,
122 .silence = { 0x7f },
123 },
124 [SNDRV_PCM_FORMAT_A_LAW] = {
125 .width = 8, .phys = 8, .le = -1, .signd = -1,
126 .silence = { 0x55 },
127 },
128 [SNDRV_PCM_FORMAT_IMA_ADPCM] = {
129 .width = 4, .phys = 4, .le = -1, .signd = -1,
130 .silence = {},
131 },
132 /* FIXME: the following three formats are not defined properly yet */
133 [SNDRV_PCM_FORMAT_MPEG] = {
134 .le = -1, .signd = -1,
135 },
136 [SNDRV_PCM_FORMAT_GSM] = {
137 .le = -1, .signd = -1,
138 },
139 [SNDRV_PCM_FORMAT_SPECIAL] = {
140 .le = -1, .signd = -1,
141 },
142 [SNDRV_PCM_FORMAT_S24_3LE] = {
143 .width = 24, .phys = 24, .le = 1, .signd = 1,
144 .silence = {},
145 },
146 [SNDRV_PCM_FORMAT_S24_3BE] = {
147 .width = 24, .phys = 24, .le = 0, .signd = 1,
148 .silence = {},
149 },
150 [SNDRV_PCM_FORMAT_U24_3LE] = {
151 .width = 24, .phys = 24, .le = 1, .signd = 0,
152 .silence = { 0x00, 0x00, 0x80 },
153 },
154 [SNDRV_PCM_FORMAT_U24_3BE] = {
155 .width = 24, .phys = 24, .le = 0, .signd = 0,
156 .silence = { 0x80, 0x00, 0x00 },
157 },
158 [SNDRV_PCM_FORMAT_S20_3LE] = {
159 .width = 20, .phys = 24, .le = 1, .signd = 1,
160 .silence = {},
161 },
162 [SNDRV_PCM_FORMAT_S20_3BE] = {
163 .width = 20, .phys = 24, .le = 0, .signd = 1,
164 .silence = {},
165 },
166 [SNDRV_PCM_FORMAT_U20_3LE] = {
167 .width = 20, .phys = 24, .le = 1, .signd = 0,
168 .silence = { 0x00, 0x00, 0x08 },
169 },
170 [SNDRV_PCM_FORMAT_U20_3BE] = {
171 .width = 20, .phys = 24, .le = 0, .signd = 0,
172 .silence = { 0x08, 0x00, 0x00 },
173 },
174 [SNDRV_PCM_FORMAT_S18_3LE] = {
175 .width = 18, .phys = 24, .le = 1, .signd = 1,
176 .silence = {},
177 },
178 [SNDRV_PCM_FORMAT_S18_3BE] = {
179 .width = 18, .phys = 24, .le = 0, .signd = 1,
180 .silence = {},
181 },
182 [SNDRV_PCM_FORMAT_U18_3LE] = {
183 .width = 18, .phys = 24, .le = 1, .signd = 0,
184 .silence = { 0x00, 0x00, 0x02 },
185 },
186 [SNDRV_PCM_FORMAT_U18_3BE] = {
187 .width = 18, .phys = 24, .le = 0, .signd = 0,
188 .silence = { 0x02, 0x00, 0x00 },
189 },
190};
191
192
193/**
194 * snd_pcm_format_signed - Check the PCM format is signed linear
195 * @format: the format to check
196 *
197 * Returns 1 if the given PCM format is signed linear, 0 if unsigned
198 * linear, and a negative error code for non-linear formats.
199 */
200int snd_pcm_format_signed(snd_pcm_format_t format)
201{
202 int val;
203 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
204 return -EINVAL;
205 if ((val = pcm_formats[format].signd) < 0)
206 return -EINVAL;
207 return val;
208}
209
210/**
211 * snd_pcm_format_unsigned - Check the PCM format is unsigned linear
212 * @format: the format to check
213 *
214 * Returns 1 if the given PCM format is unsigned linear, 0 if signed
215 * linear, and a negative error code for non-linear formats.
216 */
217int snd_pcm_format_unsigned(snd_pcm_format_t format)
218{
219 int val;
220
221 val = snd_pcm_format_signed(format);
222 if (val < 0)
223 return val;
224 return !val;
225}
226
227/**
228 * snd_pcm_format_linear - Check the PCM format is linear
229 * @format: the format to check
230 *
231 * Returns 1 if the given PCM format is linear, 0 if not.
232 */
233int snd_pcm_format_linear(snd_pcm_format_t format)
234{
235 return snd_pcm_format_signed(format) >= 0;
236}
237
238/**
239 * snd_pcm_format_little_endian - Check the PCM format is little-endian
240 * @format: the format to check
241 *
242 * Returns 1 if the given PCM format is little-endian, 0 if
243 * big-endian, or a negative error code if endian not specified.
244 */
245int snd_pcm_format_little_endian(snd_pcm_format_t format)
246{
247 int val;
248 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
249 return -EINVAL;
250 if ((val = pcm_formats[format].le) < 0)
251 return -EINVAL;
252 return val;
253}
254
255/**
256 * snd_pcm_format_big_endian - Check the PCM format is big-endian
257 * @format: the format to check
258 *
259 * Returns 1 if the given PCM format is big-endian, 0 if
260 * little-endian, or a negative error code if endian not specified.
261 */
262int snd_pcm_format_big_endian(snd_pcm_format_t format)
263{
264 int val;
265
266 val = snd_pcm_format_little_endian(format);
267 if (val < 0)
268 return val;
269 return !val;
270}
271
272/**
273 * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian
274 * @format: the format to check
275 *
276 * Returns 1 if the given PCM format is CPU-endian, 0 if
277 * opposite, or a negative error code if endian not specified.
278 */
279int snd_pcm_format_cpu_endian(snd_pcm_format_t format)
280{
281#ifdef SNDRV_LITTLE_ENDIAN
282 return snd_pcm_format_little_endian(format);
283#else
284 return snd_pcm_format_big_endian(format);
285#endif
286}
287
288/**
289 * snd_pcm_format_width - return the bit-width of the format
290 * @format: the format to check
291 *
292 * Returns the bit-width of the format, or a negative error code
293 * if unknown format.
294 */
295int snd_pcm_format_width(snd_pcm_format_t format)
296{
297 int val;
298 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
299 return -EINVAL;
300 if ((val = pcm_formats[format].width) == 0)
301 return -EINVAL;
302 return val;
303}
304
305/**
306 * snd_pcm_format_physical_width - return the physical bit-width of the format
307 * @format: the format to check
308 *
309 * Returns the physical bit-width of the format, or a negative error code
310 * if unknown format.
311 */
312int snd_pcm_format_physical_width(snd_pcm_format_t format)
313{
314 int val;
315 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
316 return -EINVAL;
317 if ((val = pcm_formats[format].phys) == 0)
318 return -EINVAL;
319 return val;
320}
321
322/**
323 * snd_pcm_format_size - return the byte size of samples on the given format
324 * @format: the format to check
325 *
326 * Returns the byte size of the given samples for the format, or a
327 * negative error code if unknown format.
328 */
329ssize_t snd_pcm_format_size(snd_pcm_format_t format, size_t samples)
330{
331 int phys_width = snd_pcm_format_physical_width(format);
332 if (phys_width < 0)
333 return -EINVAL;
334 return samples * phys_width / 8;
335}
336
337/**
338 * snd_pcm_format_silence_64 - return the silent data in 8 bytes array
339 * @format: the format to check
340 *
341 * Returns the format pattern to fill or NULL if error.
342 */
343const unsigned char *snd_pcm_format_silence_64(snd_pcm_format_t format)
344{
345 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
346 return NULL;
347 if (! pcm_formats[format].phys)
348 return NULL;
349 return pcm_formats[format].silence;
350}
351
352/**
353 * snd_pcm_format_set_silence - set the silence data on the buffer
354 * @format: the PCM format
355 * @data: the buffer pointer
356 * @samples: the number of samples to set silence
357 *
358 * Sets the silence data on the buffer for the given samples.
359 *
360 * Returns zero if successful, or a negative error code on failure.
361 */
362int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int samples)
363{
364 int width;
365 unsigned char *dst, *pat;
366
367 if (format < 0 || format > SNDRV_PCM_FORMAT_LAST)
368 return -EINVAL;
369 if (samples == 0)
370 return 0;
371 width = pcm_formats[format].phys; /* physical width */
372 pat = pcm_formats[format].silence;
373 if (! width)
374 return -EINVAL;
375 /* signed or 1 byte data */
376 if (pcm_formats[format].signd == 1 || width <= 8) {
377 unsigned int bytes = samples * width / 8;
378 memset(data, *pat, bytes);
379 return 0;
380 }
381 /* non-zero samples, fill using a loop */
382 width /= 8;
383 dst = data;
384#if 0
385 while (samples--) {
386 memcpy(dst, pat, width);
387 dst += width;
388 }
389#else
390 /* a bit optimization for constant width */
391 switch (width) {
392 case 2:
393 while (samples--) {
394 memcpy(dst, pat, 2);
395 dst += 2;
396 }
397 break;
398 case 3:
399 while (samples--) {
400 memcpy(dst, pat, 3);
401 dst += 3;
402 }
403 break;
404 case 4:
405 while (samples--) {
406 memcpy(dst, pat, 4);
407 dst += 4;
408 }
409 break;
410 case 8:
411 while (samples--) {
412 memcpy(dst, pat, 8);
413 dst += 8;
414 }
415 break;
416 }
417#endif
418 return 0;
419}
420
421/* [width][unsigned][bigendian] */
422static int linear_formats[4][2][2] = {
423 {{ SNDRV_PCM_FORMAT_S8, SNDRV_PCM_FORMAT_S8},
424 { SNDRV_PCM_FORMAT_U8, SNDRV_PCM_FORMAT_U8}},
425 {{SNDRV_PCM_FORMAT_S16_LE, SNDRV_PCM_FORMAT_S16_BE},
426 {SNDRV_PCM_FORMAT_U16_LE, SNDRV_PCM_FORMAT_U16_BE}},
427 {{SNDRV_PCM_FORMAT_S24_LE, SNDRV_PCM_FORMAT_S24_BE},
428 {SNDRV_PCM_FORMAT_U24_LE, SNDRV_PCM_FORMAT_U24_BE}},
429 {{SNDRV_PCM_FORMAT_S32_LE, SNDRV_PCM_FORMAT_S32_BE},
430 {SNDRV_PCM_FORMAT_U32_LE, SNDRV_PCM_FORMAT_U32_BE}}
431};
432
433/**
434 * snd_pcm_build_linear_format - return the suitable linear format for the given condition
435 * @width: the bit-width
436 * @unsignd: 1 if unsigned, 0 if signed.
437 * @big_endian: 1 if big-endian, 0 if little-endian
438 *
439 * Returns the suitable linear format for the given condition.
440 */
441snd_pcm_format_t snd_pcm_build_linear_format(int width, int unsignd, int big_endian)
442{
443 if (width & 7)
444 return SND_PCM_FORMAT_UNKNOWN;
445 width = (width / 8) - 1;
446 if (width < 0 || width >= 4)
447 return SND_PCM_FORMAT_UNKNOWN;
448 return linear_formats[width][!!unsignd][!!big_endian];
449}
450
451/**
452 * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields
453 * @runtime: the runtime instance
454 *
455 * Determines the rate_min and rate_max fields from the rates bits of
456 * the given runtime->hw.
457 *
458 * Returns zero if successful.
459 */
460int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime)
461{
462 static unsigned rates[] = {
463 /* ATTENTION: these values depend on the definition in pcm.h! */
464 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
465 64000, 88200, 96000, 176400, 192000
466 };
467 int i;
468 for (i = 0; i < (int)ARRAY_SIZE(rates); i++) {
469 if (runtime->hw.rates & (1 << i)) {
470 runtime->hw.rate_min = rates[i];
471 break;
472 }
473 }
474 for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) {
475 if (runtime->hw.rates & (1 << i)) {
476 runtime->hw.rate_max = rates[i];
477 break;
478 }
479 }
480 return 0;
481}
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
new file mode 100644
index 000000000000..cad9bbde9986
--- /dev/null
+++ b/sound/core/pcm_native.c
@@ -0,0 +1,3364 @@
1/*
2 * Digital Audio (PCM) abstract layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/mm.h>
24#include <linux/smp_lock.h>
25#include <linux/file.h>
26#include <linux/slab.h>
27#include <linux/time.h>
28#include <linux/uio.h>
29#include <sound/core.h>
30#include <sound/control.h>
31#include <sound/info.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include <sound/timer.h>
35#include <sound/minors.h>
36#include <asm/io.h>
37
38/*
39 * Compatibility
40 */
41
42struct sndrv_pcm_hw_params_old {
43 unsigned int flags;
44 unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
45 SNDRV_PCM_HW_PARAM_ACCESS + 1];
46 struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
47 SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
48 unsigned int rmask;
49 unsigned int cmask;
50 unsigned int info;
51 unsigned int msbits;
52 unsigned int rate_num;
53 unsigned int rate_den;
54 sndrv_pcm_uframes_t fifo_size;
55 unsigned char reserved[64];
56};
57
58#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old)
59#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old)
60
61static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams);
62static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams);
63
64/*
65 *
66 */
67
68DEFINE_RWLOCK(snd_pcm_link_rwlock);
69static DECLARE_RWSEM(snd_pcm_link_rwsem);
70
71
72static inline mm_segment_t snd_enter_user(void)
73{
74 mm_segment_t fs = get_fs();
75 set_fs(get_ds());
76 return fs;
77}
78
79static inline void snd_leave_user(mm_segment_t fs)
80{
81 set_fs(fs);
82}
83
84
85
86int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info)
87{
88 snd_pcm_runtime_t * runtime;
89 snd_pcm_t *pcm = substream->pcm;
90 snd_pcm_str_t *pstr = substream->pstr;
91
92 snd_assert(substream != NULL, return -ENXIO);
93 memset(info, 0, sizeof(*info));
94 info->card = pcm->card->number;
95 info->device = pcm->device;
96 info->stream = substream->stream;
97 info->subdevice = substream->number;
98 strlcpy(info->id, pcm->id, sizeof(info->id));
99 strlcpy(info->name, pcm->name, sizeof(info->name));
100 info->dev_class = pcm->dev_class;
101 info->dev_subclass = pcm->dev_subclass;
102 info->subdevices_count = pstr->substream_count;
103 info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
104 strlcpy(info->subname, substream->name, sizeof(info->subname));
105 runtime = substream->runtime;
106 /* AB: FIXME!!! This is definitely nonsense */
107 if (runtime) {
108 info->sync = runtime->sync;
109 substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info);
110 }
111 return 0;
112}
113
114int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t __user * _info)
115{
116 snd_pcm_info_t *info;
117 int err;
118
119 info = kmalloc(sizeof(*info), GFP_KERNEL);
120 if (! info)
121 return -ENOMEM;
122 err = snd_pcm_info(substream, info);
123 if (err >= 0) {
124 if (copy_to_user(_info, info, sizeof(*info)))
125 err = -EFAULT;
126 }
127 kfree(info);
128 return err;
129}
130
131#undef RULES_DEBUG
132
133#ifdef RULES_DEBUG
134#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
135char *snd_pcm_hw_param_names[] = {
136 HW_PARAM(ACCESS),
137 HW_PARAM(FORMAT),
138 HW_PARAM(SUBFORMAT),
139 HW_PARAM(SAMPLE_BITS),
140 HW_PARAM(FRAME_BITS),
141 HW_PARAM(CHANNELS),
142 HW_PARAM(RATE),
143 HW_PARAM(PERIOD_TIME),
144 HW_PARAM(PERIOD_SIZE),
145 HW_PARAM(PERIOD_BYTES),
146 HW_PARAM(PERIODS),
147 HW_PARAM(BUFFER_TIME),
148 HW_PARAM(BUFFER_SIZE),
149 HW_PARAM(BUFFER_BYTES),
150 HW_PARAM(TICK_TIME),
151};
152#endif
153
154int snd_pcm_hw_refine(snd_pcm_substream_t *substream,
155 snd_pcm_hw_params_t *params)
156{
157 unsigned int k;
158 snd_pcm_hardware_t *hw;
159 snd_interval_t *i = NULL;
160 snd_mask_t *m = NULL;
161 snd_pcm_hw_constraints_t *constrs = &substream->runtime->hw_constraints;
162 unsigned int rstamps[constrs->rules_num];
163 unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
164 unsigned int stamp = 2;
165 int changed, again;
166
167 params->info = 0;
168 params->fifo_size = 0;
169 if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))
170 params->msbits = 0;
171 if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {
172 params->rate_num = 0;
173 params->rate_den = 0;
174 }
175
176 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
177 m = hw_param_mask(params, k);
178 if (snd_mask_empty(m))
179 return -EINVAL;
180 if (!(params->rmask & (1 << k)))
181 continue;
182#ifdef RULES_DEBUG
183 printk("%s = ", snd_pcm_hw_param_names[k]);
184 printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
185#endif
186 changed = snd_mask_refine(m, constrs_mask(constrs, k));
187#ifdef RULES_DEBUG
188 printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
189#endif
190 if (changed)
191 params->cmask |= 1 << k;
192 if (changed < 0)
193 return changed;
194 }
195
196 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
197 i = hw_param_interval(params, k);
198 if (snd_interval_empty(i))
199 return -EINVAL;
200 if (!(params->rmask & (1 << k)))
201 continue;
202#ifdef RULES_DEBUG
203 printk("%s = ", snd_pcm_hw_param_names[k]);
204 if (i->empty)
205 printk("empty");
206 else
207 printk("%c%u %u%c",
208 i->openmin ? '(' : '[', i->min,
209 i->max, i->openmax ? ')' : ']');
210 printk(" -> ");
211#endif
212 changed = snd_interval_refine(i, constrs_interval(constrs, k));
213#ifdef RULES_DEBUG
214 if (i->empty)
215 printk("empty\n");
216 else
217 printk("%c%u %u%c\n",
218 i->openmin ? '(' : '[', i->min,
219 i->max, i->openmax ? ')' : ']');
220#endif
221 if (changed)
222 params->cmask |= 1 << k;
223 if (changed < 0)
224 return changed;
225 }
226
227 for (k = 0; k < constrs->rules_num; k++)
228 rstamps[k] = 0;
229 for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
230 vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
231 do {
232 again = 0;
233 for (k = 0; k < constrs->rules_num; k++) {
234 snd_pcm_hw_rule_t *r = &constrs->rules[k];
235 unsigned int d;
236 int doit = 0;
237 if (r->cond && !(r->cond & params->flags))
238 continue;
239 for (d = 0; r->deps[d] >= 0; d++) {
240 if (vstamps[r->deps[d]] > rstamps[k]) {
241 doit = 1;
242 break;
243 }
244 }
245 if (!doit)
246 continue;
247#ifdef RULES_DEBUG
248 printk("Rule %d [%p]: ", k, r->func);
249 if (r->var >= 0) {
250 printk("%s = ", snd_pcm_hw_param_names[r->var]);
251 if (hw_is_mask(r->var)) {
252 m = hw_param_mask(params, r->var);
253 printk("%x", *m->bits);
254 } else {
255 i = hw_param_interval(params, r->var);
256 if (i->empty)
257 printk("empty");
258 else
259 printk("%c%u %u%c",
260 i->openmin ? '(' : '[', i->min,
261 i->max, i->openmax ? ')' : ']');
262 }
263 }
264#endif
265 changed = r->func(params, r);
266#ifdef RULES_DEBUG
267 if (r->var >= 0) {
268 printk(" -> ");
269 if (hw_is_mask(r->var))
270 printk("%x", *m->bits);
271 else {
272 if (i->empty)
273 printk("empty");
274 else
275 printk("%c%u %u%c",
276 i->openmin ? '(' : '[', i->min,
277 i->max, i->openmax ? ')' : ']');
278 }
279 }
280 printk("\n");
281#endif
282 rstamps[k] = stamp;
283 if (changed && r->var >= 0) {
284 params->cmask |= (1 << r->var);
285 vstamps[r->var] = stamp;
286 again = 1;
287 }
288 if (changed < 0)
289 return changed;
290 stamp++;
291 }
292 } while (again);
293 if (!params->msbits) {
294 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
295 if (snd_interval_single(i))
296 params->msbits = snd_interval_value(i);
297 }
298
299 if (!params->rate_den) {
300 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
301 if (snd_interval_single(i)) {
302 params->rate_num = snd_interval_value(i);
303 params->rate_den = 1;
304 }
305 }
306
307 hw = &substream->runtime->hw;
308 if (!params->info)
309 params->info = hw->info;
310 if (!params->fifo_size)
311 params->fifo_size = hw->fifo_size;
312 params->rmask = 0;
313 return 0;
314}
315
316static int snd_pcm_hw_refine_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params)
317{
318 snd_pcm_hw_params_t *params;
319 int err;
320
321 params = kmalloc(sizeof(*params), GFP_KERNEL);
322 if (!params) {
323 err = -ENOMEM;
324 goto out;
325 }
326 if (copy_from_user(params, _params, sizeof(*params))) {
327 err = -EFAULT;
328 goto out;
329 }
330 err = snd_pcm_hw_refine(substream, params);
331 if (copy_to_user(_params, params, sizeof(*params))) {
332 if (!err)
333 err = -EFAULT;
334 }
335out:
336 kfree(params);
337 return err;
338}
339
340int snd_pcm_hw_params(snd_pcm_substream_t *substream,
341 snd_pcm_hw_params_t *params)
342{
343 snd_pcm_runtime_t *runtime;
344 int err;
345 unsigned int bits;
346 snd_pcm_uframes_t frames;
347
348 snd_assert(substream != NULL, return -ENXIO);
349 runtime = substream->runtime;
350 snd_assert(runtime != NULL, return -ENXIO);
351 snd_pcm_stream_lock_irq(substream);
352 switch (runtime->status->state) {
353 case SNDRV_PCM_STATE_OPEN:
354 case SNDRV_PCM_STATE_SETUP:
355 case SNDRV_PCM_STATE_PREPARED:
356 break;
357 default:
358 snd_pcm_stream_unlock_irq(substream);
359 return -EBADFD;
360 }
361 snd_pcm_stream_unlock_irq(substream);
362#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
363 if (!substream->oss.oss)
364#endif
365 if (atomic_read(&runtime->mmap_count))
366 return -EBADFD;
367
368 params->rmask = ~0U;
369 err = snd_pcm_hw_refine(substream, params);
370 if (err < 0)
371 goto _error;
372
373 err = snd_pcm_hw_params_choose(substream, params);
374 if (err < 0)
375 goto _error;
376
377 if (substream->ops->hw_params != NULL) {
378 err = substream->ops->hw_params(substream, params);
379 if (err < 0)
380 goto _error;
381 }
382
383 runtime->access = params_access(params);
384 runtime->format = params_format(params);
385 runtime->subformat = params_subformat(params);
386 runtime->channels = params_channels(params);
387 runtime->rate = params_rate(params);
388 runtime->period_size = params_period_size(params);
389 runtime->periods = params_periods(params);
390 runtime->buffer_size = params_buffer_size(params);
391 runtime->tick_time = params_tick_time(params);
392 runtime->info = params->info;
393 runtime->rate_num = params->rate_num;
394 runtime->rate_den = params->rate_den;
395
396 bits = snd_pcm_format_physical_width(runtime->format);
397 runtime->sample_bits = bits;
398 bits *= runtime->channels;
399 runtime->frame_bits = bits;
400 frames = 1;
401 while (bits % 8 != 0) {
402 bits *= 2;
403 frames *= 2;
404 }
405 runtime->byte_align = bits / 8;
406 runtime->min_align = frames;
407
408 /* Default sw params */
409 runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
410 runtime->period_step = 1;
411 runtime->sleep_min = 0;
412 runtime->control->avail_min = runtime->period_size;
413 runtime->xfer_align = runtime->period_size;
414 runtime->start_threshold = 1;
415 runtime->stop_threshold = runtime->buffer_size;
416 runtime->silence_threshold = 0;
417 runtime->silence_size = 0;
418 runtime->boundary = runtime->buffer_size;
419 while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
420 runtime->boundary *= 2;
421
422 snd_pcm_timer_resolution_change(substream);
423 runtime->status->state = SNDRV_PCM_STATE_SETUP;
424 return 0;
425 _error:
426 /* hardware might be unuseable from this time,
427 so we force application to retry to set
428 the correct hardware parameter settings */
429 runtime->status->state = SNDRV_PCM_STATE_OPEN;
430 if (substream->ops->hw_free != NULL)
431 substream->ops->hw_free(substream);
432 return err;
433}
434
435static int snd_pcm_hw_params_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params)
436{
437 snd_pcm_hw_params_t *params;
438 int err;
439
440 params = kmalloc(sizeof(*params), GFP_KERNEL);
441 if (!params) {
442 err = -ENOMEM;
443 goto out;
444 }
445 if (copy_from_user(params, _params, sizeof(*params))) {
446 err = -EFAULT;
447 goto out;
448 }
449 err = snd_pcm_hw_params(substream, params);
450 if (copy_to_user(_params, params, sizeof(*params))) {
451 if (!err)
452 err = -EFAULT;
453 }
454out:
455 kfree(params);
456 return err;
457}
458
459static int snd_pcm_hw_free(snd_pcm_substream_t * substream)
460{
461 snd_pcm_runtime_t *runtime;
462 int result = 0;
463
464 snd_assert(substream != NULL, return -ENXIO);
465 runtime = substream->runtime;
466 snd_assert(runtime != NULL, return -ENXIO);
467 snd_pcm_stream_lock_irq(substream);
468 switch (runtime->status->state) {
469 case SNDRV_PCM_STATE_SETUP:
470 case SNDRV_PCM_STATE_PREPARED:
471 break;
472 default:
473 snd_pcm_stream_unlock_irq(substream);
474 return -EBADFD;
475 }
476 snd_pcm_stream_unlock_irq(substream);
477 if (atomic_read(&runtime->mmap_count))
478 return -EBADFD;
479 if (substream->ops->hw_free)
480 result = substream->ops->hw_free(substream);
481 runtime->status->state = SNDRV_PCM_STATE_OPEN;
482 return result;
483}
484
485static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_t *params)
486{
487 snd_pcm_runtime_t *runtime;
488
489 snd_assert(substream != NULL, return -ENXIO);
490 runtime = substream->runtime;
491 snd_assert(runtime != NULL, return -ENXIO);
492 snd_pcm_stream_lock_irq(substream);
493 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
494 snd_pcm_stream_unlock_irq(substream);
495 return -EBADFD;
496 }
497 snd_pcm_stream_unlock_irq(substream);
498
499 if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
500 return -EINVAL;
501 if (params->avail_min == 0)
502 return -EINVAL;
503 if (params->xfer_align == 0 ||
504 params->xfer_align % runtime->min_align != 0)
505 return -EINVAL;
506 if (params->silence_size >= runtime->boundary) {
507 if (params->silence_threshold != 0)
508 return -EINVAL;
509 } else {
510 if (params->silence_size > params->silence_threshold)
511 return -EINVAL;
512 if (params->silence_threshold > runtime->buffer_size)
513 return -EINVAL;
514 }
515 snd_pcm_stream_lock_irq(substream);
516 runtime->tstamp_mode = params->tstamp_mode;
517 runtime->sleep_min = params->sleep_min;
518 runtime->period_step = params->period_step;
519 runtime->control->avail_min = params->avail_min;
520 runtime->start_threshold = params->start_threshold;
521 runtime->stop_threshold = params->stop_threshold;
522 runtime->silence_threshold = params->silence_threshold;
523 runtime->silence_size = params->silence_size;
524 runtime->xfer_align = params->xfer_align;
525 params->boundary = runtime->boundary;
526 if (snd_pcm_running(substream)) {
527 if (runtime->sleep_min)
528 snd_pcm_tick_prepare(substream);
529 else
530 snd_pcm_tick_set(substream, 0);
531 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
532 runtime->silence_size > 0)
533 snd_pcm_playback_silence(substream, ULONG_MAX);
534 wake_up(&runtime->sleep);
535 }
536 snd_pcm_stream_unlock_irq(substream);
537 return 0;
538}
539
540static int snd_pcm_sw_params_user(snd_pcm_substream_t * substream, snd_pcm_sw_params_t __user * _params)
541{
542 snd_pcm_sw_params_t params;
543 int err;
544 if (copy_from_user(&params, _params, sizeof(params)))
545 return -EFAULT;
546 err = snd_pcm_sw_params(substream, &params);
547 if (copy_to_user(_params, &params, sizeof(params)))
548 return -EFAULT;
549 return err;
550}
551
552int snd_pcm_status(snd_pcm_substream_t *substream,
553 snd_pcm_status_t *status)
554{
555 snd_pcm_runtime_t *runtime = substream->runtime;
556
557 snd_pcm_stream_lock_irq(substream);
558 status->state = runtime->status->state;
559 status->suspended_state = runtime->status->suspended_state;
560 if (status->state == SNDRV_PCM_STATE_OPEN)
561 goto _end;
562 status->trigger_tstamp = runtime->trigger_tstamp;
563 if (snd_pcm_running(substream)) {
564 snd_pcm_update_hw_ptr(substream);
565 if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP)
566 status->tstamp = runtime->status->tstamp;
567 else
568 snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
569 } else
570 snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec);
571 status->appl_ptr = runtime->control->appl_ptr;
572 status->hw_ptr = runtime->status->hw_ptr;
573 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
574 status->avail = snd_pcm_playback_avail(runtime);
575 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
576 runtime->status->state == SNDRV_PCM_STATE_DRAINING)
577 status->delay = runtime->buffer_size - status->avail;
578 else
579 status->delay = 0;
580 } else {
581 status->avail = snd_pcm_capture_avail(runtime);
582 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
583 status->delay = status->avail;
584 else
585 status->delay = 0;
586 }
587 status->avail_max = runtime->avail_max;
588 status->overrange = runtime->overrange;
589 runtime->avail_max = 0;
590 runtime->overrange = 0;
591 _end:
592 snd_pcm_stream_unlock_irq(substream);
593 return 0;
594}
595
596static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t __user * _status)
597{
598 snd_pcm_status_t status;
599 snd_pcm_runtime_t *runtime;
600 int res;
601
602 snd_assert(substream != NULL, return -ENXIO);
603 runtime = substream->runtime;
604 memset(&status, 0, sizeof(status));
605 res = snd_pcm_status(substream, &status);
606 if (res < 0)
607 return res;
608 if (copy_to_user(_status, &status, sizeof(status)))
609 return -EFAULT;
610 return 0;
611}
612
613static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t * info)
614{
615 snd_pcm_runtime_t *runtime;
616 unsigned int channel;
617
618 snd_assert(substream != NULL, return -ENXIO);
619 channel = info->channel;
620 runtime = substream->runtime;
621 snd_pcm_stream_lock_irq(substream);
622 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
623 snd_pcm_stream_unlock_irq(substream);
624 return -EBADFD;
625 }
626 snd_pcm_stream_unlock_irq(substream);
627 if (channel >= runtime->channels)
628 return -EINVAL;
629 memset(info, 0, sizeof(*info));
630 info->channel = channel;
631 return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);
632}
633
634static int snd_pcm_channel_info_user(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info)
635{
636 snd_pcm_channel_info_t info;
637 int res;
638
639 if (copy_from_user(&info, _info, sizeof(info)))
640 return -EFAULT;
641 res = snd_pcm_channel_info(substream, &info);
642 if (res < 0)
643 return res;
644 if (copy_to_user(_info, &info, sizeof(info)))
645 return -EFAULT;
646 return 0;
647}
648
649static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream)
650{
651 snd_pcm_runtime_t *runtime = substream->runtime;
652 if (runtime->trigger_master == NULL)
653 return;
654 if (runtime->trigger_master == substream) {
655 snd_timestamp_now(&runtime->trigger_tstamp, runtime->tstamp_timespec);
656 } else {
657 snd_pcm_trigger_tstamp(runtime->trigger_master);
658 runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
659 }
660 runtime->trigger_master = NULL;
661}
662
663struct action_ops {
664 int (*pre_action)(snd_pcm_substream_t *substream, int state);
665 int (*do_action)(snd_pcm_substream_t *substream, int state);
666 void (*undo_action)(snd_pcm_substream_t *substream, int state);
667 void (*post_action)(snd_pcm_substream_t *substream, int state);
668};
669
670/*
671 * this functions is core for handling of linked stream
672 * Note: the stream state might be changed also on failure
673 * Note2: call with calling stream lock + link lock
674 */
675static int snd_pcm_action_group(struct action_ops *ops,
676 snd_pcm_substream_t *substream,
677 int state, int do_lock)
678{
679 struct list_head *pos;
680 snd_pcm_substream_t *s = NULL;
681 snd_pcm_substream_t *s1;
682 int res = 0;
683
684 snd_pcm_group_for_each(pos, substream) {
685 s = snd_pcm_group_substream_entry(pos);
686 if (do_lock && s != substream)
687 spin_lock(&s->self_group.lock);
688 res = ops->pre_action(s, state);
689 if (res < 0)
690 goto _unlock;
691 }
692 snd_pcm_group_for_each(pos, substream) {
693 s = snd_pcm_group_substream_entry(pos);
694 res = ops->do_action(s, state);
695 if (res < 0) {
696 if (ops->undo_action) {
697 snd_pcm_group_for_each(pos, substream) {
698 s1 = snd_pcm_group_substream_entry(pos);
699 if (s1 == s) /* failed stream */
700 break;
701 ops->undo_action(s1, state);
702 }
703 }
704 s = NULL; /* unlock all */
705 goto _unlock;
706 }
707 }
708 snd_pcm_group_for_each(pos, substream) {
709 s = snd_pcm_group_substream_entry(pos);
710 ops->post_action(s, state);
711 }
712 _unlock:
713 if (do_lock) {
714 /* unlock streams */
715 snd_pcm_group_for_each(pos, substream) {
716 s1 = snd_pcm_group_substream_entry(pos);
717 if (s1 != substream)
718 spin_unlock(&s1->self_group.lock);
719 if (s1 == s) /* end */
720 break;
721 }
722 }
723 return res;
724}
725
726/*
727 * Note: call with stream lock
728 */
729static int snd_pcm_action_single(struct action_ops *ops,
730 snd_pcm_substream_t *substream,
731 int state)
732{
733 int res;
734
735 res = ops->pre_action(substream, state);
736 if (res < 0)
737 return res;
738 res = ops->do_action(substream, state);
739 if (res == 0)
740 ops->post_action(substream, state);
741 else if (ops->undo_action)
742 ops->undo_action(substream, state);
743 return res;
744}
745
746/*
747 * Note: call with stream lock
748 */
749static int snd_pcm_action(struct action_ops *ops,
750 snd_pcm_substream_t *substream,
751 int state)
752{
753 int res;
754
755 if (snd_pcm_stream_linked(substream)) {
756 if (!spin_trylock(&substream->group->lock)) {
757 spin_unlock(&substream->self_group.lock);
758 spin_lock(&substream->group->lock);
759 spin_lock(&substream->self_group.lock);
760 }
761 res = snd_pcm_action_group(ops, substream, state, 1);
762 spin_unlock(&substream->group->lock);
763 } else {
764 res = snd_pcm_action_single(ops, substream, state);
765 }
766 return res;
767}
768
769/*
770 * Note: don't use any locks before
771 */
772static int snd_pcm_action_lock_irq(struct action_ops *ops,
773 snd_pcm_substream_t *substream,
774 int state)
775{
776 int res;
777
778 read_lock_irq(&snd_pcm_link_rwlock);
779 if (snd_pcm_stream_linked(substream)) {
780 spin_lock(&substream->group->lock);
781 spin_lock(&substream->self_group.lock);
782 res = snd_pcm_action_group(ops, substream, state, 1);
783 spin_unlock(&substream->self_group.lock);
784 spin_unlock(&substream->group->lock);
785 } else {
786 spin_lock(&substream->self_group.lock);
787 res = snd_pcm_action_single(ops, substream, state);
788 spin_unlock(&substream->self_group.lock);
789 }
790 read_unlock_irq(&snd_pcm_link_rwlock);
791 return res;
792}
793
794/*
795 */
796static int snd_pcm_action_nonatomic(struct action_ops *ops,
797 snd_pcm_substream_t *substream,
798 int state)
799{
800 int res;
801
802 down_read(&snd_pcm_link_rwsem);
803 if (snd_pcm_stream_linked(substream))
804 res = snd_pcm_action_group(ops, substream, state, 0);
805 else
806 res = snd_pcm_action_single(ops, substream, state);
807 up_read(&snd_pcm_link_rwsem);
808 return res;
809}
810
811/*
812 * start callbacks
813 */
814static int snd_pcm_pre_start(snd_pcm_substream_t *substream, int state)
815{
816 snd_pcm_runtime_t *runtime = substream->runtime;
817 if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
818 return -EBADFD;
819 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
820 !snd_pcm_playback_data(substream))
821 return -EPIPE;
822 runtime->trigger_master = substream;
823 return 0;
824}
825
826static int snd_pcm_do_start(snd_pcm_substream_t *substream, int state)
827{
828 if (substream->runtime->trigger_master != substream)
829 return 0;
830 return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
831}
832
833static void snd_pcm_undo_start(snd_pcm_substream_t *substream, int state)
834{
835 if (substream->runtime->trigger_master == substream)
836 substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
837}
838
839static void snd_pcm_post_start(snd_pcm_substream_t *substream, int state)
840{
841 snd_pcm_runtime_t *runtime = substream->runtime;
842 snd_pcm_trigger_tstamp(substream);
843 runtime->status->state = state;
844 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
845 runtime->silence_size > 0)
846 snd_pcm_playback_silence(substream, ULONG_MAX);
847 if (runtime->sleep_min)
848 snd_pcm_tick_prepare(substream);
849 if (substream->timer)
850 snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp);
851}
852
853static struct action_ops snd_pcm_action_start = {
854 .pre_action = snd_pcm_pre_start,
855 .do_action = snd_pcm_do_start,
856 .undo_action = snd_pcm_undo_start,
857 .post_action = snd_pcm_post_start
858};
859
860/**
861 * snd_pcm_start
862 *
863 * Start all linked streams.
864 */
865int snd_pcm_start(snd_pcm_substream_t *substream)
866{
867 return snd_pcm_action(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
868}
869
870/*
871 * stop callbacks
872 */
873static int snd_pcm_pre_stop(snd_pcm_substream_t *substream, int state)
874{
875 snd_pcm_runtime_t *runtime = substream->runtime;
876 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
877 return -EBADFD;
878 runtime->trigger_master = substream;
879 return 0;
880}
881
882static int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state)
883{
884 if (substream->runtime->trigger_master == substream &&
885 snd_pcm_running(substream))
886 substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
887 return 0; /* unconditonally stop all substreams */
888}
889
890static void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state)
891{
892 snd_pcm_runtime_t *runtime = substream->runtime;
893 if (runtime->status->state != state) {
894 snd_pcm_trigger_tstamp(substream);
895 if (substream->timer)
896 snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp);
897 runtime->status->state = state;
898 snd_pcm_tick_set(substream, 0);
899 }
900 wake_up(&runtime->sleep);
901}
902
903static struct action_ops snd_pcm_action_stop = {
904 .pre_action = snd_pcm_pre_stop,
905 .do_action = snd_pcm_do_stop,
906 .post_action = snd_pcm_post_stop
907};
908
909/**
910 * snd_pcm_stop
911 *
912 * Try to stop all running streams in the substream group.
913 * The state of each stream is changed to the given value after that unconditionally.
914 */
915int snd_pcm_stop(snd_pcm_substream_t *substream, int state)
916{
917 return snd_pcm_action(&snd_pcm_action_stop, substream, state);
918}
919
920/**
921 * snd_pcm_drain_done
922 *
923 * Stop the DMA only when the given stream is playback.
924 * The state is changed to SETUP.
925 * Unlike snd_pcm_stop(), this affects only the given stream.
926 */
927int snd_pcm_drain_done(snd_pcm_substream_t *substream)
928{
929 return snd_pcm_action_single(&snd_pcm_action_stop, substream, SNDRV_PCM_STATE_SETUP);
930}
931
932/*
933 * pause callbacks
934 */
935static int snd_pcm_pre_pause(snd_pcm_substream_t *substream, int push)
936{
937 snd_pcm_runtime_t *runtime = substream->runtime;
938 if (!(runtime->info & SNDRV_PCM_INFO_PAUSE))
939 return -ENOSYS;
940 if (push) {
941 if (runtime->status->state != SNDRV_PCM_STATE_RUNNING)
942 return -EBADFD;
943 } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED)
944 return -EBADFD;
945 runtime->trigger_master = substream;
946 return 0;
947}
948
949static int snd_pcm_do_pause(snd_pcm_substream_t *substream, int push)
950{
951 if (substream->runtime->trigger_master != substream)
952 return 0;
953 return substream->ops->trigger(substream,
954 push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
955 SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
956}
957
958static void snd_pcm_undo_pause(snd_pcm_substream_t *substream, int push)
959{
960 if (substream->runtime->trigger_master == substream)
961 substream->ops->trigger(substream,
962 push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
963 SNDRV_PCM_TRIGGER_PAUSE_PUSH);
964}
965
966static void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push)
967{
968 snd_pcm_runtime_t *runtime = substream->runtime;
969 snd_pcm_trigger_tstamp(substream);
970 if (push) {
971 runtime->status->state = SNDRV_PCM_STATE_PAUSED;
972 if (substream->timer)
973 snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
974 snd_pcm_tick_set(substream, 0);
975 wake_up(&runtime->sleep);
976 } else {
977 runtime->status->state = SNDRV_PCM_STATE_RUNNING;
978 if (runtime->sleep_min)
979 snd_pcm_tick_prepare(substream);
980 if (substream->timer)
981 snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
982 }
983}
984
985static struct action_ops snd_pcm_action_pause = {
986 .pre_action = snd_pcm_pre_pause,
987 .do_action = snd_pcm_do_pause,
988 .undo_action = snd_pcm_undo_pause,
989 .post_action = snd_pcm_post_pause
990};
991
992/*
993 * Push/release the pause for all linked streams.
994 */
995static int snd_pcm_pause(snd_pcm_substream_t *substream, int push)
996{
997 return snd_pcm_action(&snd_pcm_action_pause, substream, push);
998}
999
1000#ifdef CONFIG_PM
1001/* suspend */
1002
1003static int snd_pcm_pre_suspend(snd_pcm_substream_t *substream, int state)
1004{
1005 snd_pcm_runtime_t *runtime = substream->runtime;
1006 if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
1007 return -EBUSY;
1008 runtime->trigger_master = substream;
1009 return 0;
1010}
1011
1012static int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state)
1013{
1014 snd_pcm_runtime_t *runtime = substream->runtime;
1015 if (runtime->trigger_master != substream)
1016 return 0;
1017 if (! snd_pcm_running(substream))
1018 return 0;
1019 substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
1020 return 0; /* suspend unconditionally */
1021}
1022
1023static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state)
1024{
1025 snd_pcm_runtime_t *runtime = substream->runtime;
1026 snd_pcm_trigger_tstamp(substream);
1027 if (substream->timer)
1028 snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp);
1029 runtime->status->suspended_state = runtime->status->state;
1030 runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
1031 snd_pcm_tick_set(substream, 0);
1032 wake_up(&runtime->sleep);
1033}
1034
1035static struct action_ops snd_pcm_action_suspend = {
1036 .pre_action = snd_pcm_pre_suspend,
1037 .do_action = snd_pcm_do_suspend,
1038 .post_action = snd_pcm_post_suspend
1039};
1040
1041/**
1042 * snd_pcm_suspend
1043 *
1044 * Trigger SUSPEND to all linked streams.
1045 * After this call, all streams are changed to SUSPENDED state.
1046 */
1047int snd_pcm_suspend(snd_pcm_substream_t *substream)
1048{
1049 int err;
1050 unsigned long flags;
1051
1052 snd_pcm_stream_lock_irqsave(substream, flags);
1053 err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0);
1054 snd_pcm_stream_unlock_irqrestore(substream, flags);
1055 return err;
1056}
1057
1058/**
1059 * snd_pcm_suspend_all
1060 *
1061 * Trigger SUSPEND to all substreams in the given pcm.
1062 * After this call, all streams are changed to SUSPENDED state.
1063 */
1064int snd_pcm_suspend_all(snd_pcm_t *pcm)
1065{
1066 snd_pcm_substream_t *substream;
1067 int stream, err = 0;
1068
1069 for (stream = 0; stream < 2; stream++) {
1070 for (substream = pcm->streams[stream].substream; substream; substream = substream->next) {
1071 /* FIXME: the open/close code should lock this as well */
1072 if (substream->runtime == NULL)
1073 continue;
1074 err = snd_pcm_suspend(substream);
1075 if (err < 0 && err != -EBUSY)
1076 return err;
1077 }
1078 }
1079 return 0;
1080}
1081
1082/* resume */
1083
1084static int snd_pcm_pre_resume(snd_pcm_substream_t *substream, int state)
1085{
1086 snd_pcm_runtime_t *runtime = substream->runtime;
1087 if (!(runtime->info & SNDRV_PCM_INFO_RESUME))
1088 return -ENOSYS;
1089 runtime->trigger_master = substream;
1090 return 0;
1091}
1092
1093static int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state)
1094{
1095 snd_pcm_runtime_t *runtime = substream->runtime;
1096 if (runtime->trigger_master != substream)
1097 return 0;
1098 /* DMA not running previously? */
1099 if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING &&
1100 (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING ||
1101 substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
1102 return 0;
1103 return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME);
1104}
1105
1106static void snd_pcm_undo_resume(snd_pcm_substream_t *substream, int state)
1107{
1108 if (substream->runtime->trigger_master == substream &&
1109 snd_pcm_running(substream))
1110 substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
1111}
1112
1113static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state)
1114{
1115 snd_pcm_runtime_t *runtime = substream->runtime;
1116 snd_pcm_trigger_tstamp(substream);
1117 if (substream->timer)
1118 snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp);
1119 runtime->status->state = runtime->status->suspended_state;
1120 if (runtime->sleep_min)
1121 snd_pcm_tick_prepare(substream);
1122}
1123
1124static struct action_ops snd_pcm_action_resume = {
1125 .pre_action = snd_pcm_pre_resume,
1126 .do_action = snd_pcm_do_resume,
1127 .undo_action = snd_pcm_undo_resume,
1128 .post_action = snd_pcm_post_resume
1129};
1130
1131static int snd_pcm_resume(snd_pcm_substream_t *substream)
1132{
1133 snd_card_t *card = substream->pcm->card;
1134 int res;
1135
1136 snd_power_lock(card);
1137 if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
1138 res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
1139 snd_power_unlock(card);
1140 return res;
1141}
1142
1143#else
1144
1145static int snd_pcm_resume(snd_pcm_substream_t *substream)
1146{
1147 return -ENOSYS;
1148}
1149
1150#endif /* CONFIG_PM */
1151
1152/*
1153 * xrun ioctl
1154 *
1155 * Change the RUNNING stream(s) to XRUN state.
1156 */
1157static int snd_pcm_xrun(snd_pcm_substream_t *substream)
1158{
1159 snd_card_t *card = substream->pcm->card;
1160 snd_pcm_runtime_t *runtime = substream->runtime;
1161 int result;
1162
1163 snd_power_lock(card);
1164 if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1165 result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
1166 if (result < 0)
1167 goto _unlock;
1168 }
1169
1170 snd_pcm_stream_lock_irq(substream);
1171 switch (runtime->status->state) {
1172 case SNDRV_PCM_STATE_XRUN:
1173 result = 0; /* already there */
1174 break;
1175 case SNDRV_PCM_STATE_RUNNING:
1176 result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
1177 break;
1178 default:
1179 result = -EBADFD;
1180 }
1181 snd_pcm_stream_unlock_irq(substream);
1182 _unlock:
1183 snd_power_unlock(card);
1184 return result;
1185}
1186
1187/*
1188 * reset ioctl
1189 */
1190static int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state)
1191{
1192 snd_pcm_runtime_t *runtime = substream->runtime;
1193 switch (runtime->status->state) {
1194 case SNDRV_PCM_STATE_RUNNING:
1195 case SNDRV_PCM_STATE_PREPARED:
1196 case SNDRV_PCM_STATE_PAUSED:
1197 case SNDRV_PCM_STATE_SUSPENDED:
1198 return 0;
1199 default:
1200 return -EBADFD;
1201 }
1202}
1203
1204static int snd_pcm_do_reset(snd_pcm_substream_t * substream, int state)
1205{
1206 snd_pcm_runtime_t *runtime = substream->runtime;
1207 int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
1208 if (err < 0)
1209 return err;
1210 // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, );
1211 runtime->hw_ptr_base = 0;
1212 runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size;
1213 runtime->silence_start = runtime->status->hw_ptr;
1214 runtime->silence_filled = 0;
1215 return 0;
1216}
1217
1218static void snd_pcm_post_reset(snd_pcm_substream_t * substream, int state)
1219{
1220 snd_pcm_runtime_t *runtime = substream->runtime;
1221 runtime->control->appl_ptr = runtime->status->hw_ptr;
1222 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
1223 runtime->silence_size > 0)
1224 snd_pcm_playback_silence(substream, ULONG_MAX);
1225}
1226
1227static struct action_ops snd_pcm_action_reset = {
1228 .pre_action = snd_pcm_pre_reset,
1229 .do_action = snd_pcm_do_reset,
1230 .post_action = snd_pcm_post_reset
1231};
1232
1233static int snd_pcm_reset(snd_pcm_substream_t *substream)
1234{
1235 return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0);
1236}
1237
1238/*
1239 * prepare ioctl
1240 */
1241static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state)
1242{
1243 snd_pcm_runtime_t *runtime = substream->runtime;
1244 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1245 return -EBADFD;
1246 if (snd_pcm_running(substream))
1247 return -EBUSY;
1248 return 0;
1249}
1250
1251static int snd_pcm_do_prepare(snd_pcm_substream_t * substream, int state)
1252{
1253 int err;
1254 err = substream->ops->prepare(substream);
1255 if (err < 0)
1256 return err;
1257 return snd_pcm_do_reset(substream, 0);
1258}
1259
1260static void snd_pcm_post_prepare(snd_pcm_substream_t * substream, int state)
1261{
1262 snd_pcm_runtime_t *runtime = substream->runtime;
1263 runtime->control->appl_ptr = runtime->status->hw_ptr;
1264 runtime->status->state = SNDRV_PCM_STATE_PREPARED;
1265}
1266
1267static struct action_ops snd_pcm_action_prepare = {
1268 .pre_action = snd_pcm_pre_prepare,
1269 .do_action = snd_pcm_do_prepare,
1270 .post_action = snd_pcm_post_prepare
1271};
1272
1273/**
1274 * snd_pcm_prepare
1275 */
1276int snd_pcm_prepare(snd_pcm_substream_t *substream)
1277{
1278 int res;
1279 snd_card_t *card = substream->pcm->card;
1280
1281 snd_power_lock(card);
1282 if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0)
1283 res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0);
1284 snd_power_unlock(card);
1285 return res;
1286}
1287
1288/*
1289 * drain ioctl
1290 */
1291
1292static int snd_pcm_pre_drain_init(snd_pcm_substream_t * substream, int state)
1293{
1294 if (substream->ffile->f_flags & O_NONBLOCK)
1295 return -EAGAIN;
1296 substream->runtime->trigger_master = substream;
1297 return 0;
1298}
1299
1300static int snd_pcm_do_drain_init(snd_pcm_substream_t * substream, int state)
1301{
1302 snd_pcm_runtime_t *runtime = substream->runtime;
1303 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1304 switch (runtime->status->state) {
1305 case SNDRV_PCM_STATE_PREPARED:
1306 /* start playback stream if possible */
1307 if (! snd_pcm_playback_empty(substream)) {
1308 snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
1309 snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
1310 }
1311 break;
1312 case SNDRV_PCM_STATE_RUNNING:
1313 runtime->status->state = SNDRV_PCM_STATE_DRAINING;
1314 break;
1315 default:
1316 break;
1317 }
1318 } else {
1319 /* stop running stream */
1320 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {
1321 int state = snd_pcm_capture_avail(runtime) > 0 ?
1322 SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP;
1323 snd_pcm_do_stop(substream, state);
1324 snd_pcm_post_stop(substream, state);
1325 }
1326 }
1327 return 0;
1328}
1329
1330static void snd_pcm_post_drain_init(snd_pcm_substream_t * substream, int state)
1331{
1332}
1333
1334static struct action_ops snd_pcm_action_drain_init = {
1335 .pre_action = snd_pcm_pre_drain_init,
1336 .do_action = snd_pcm_do_drain_init,
1337 .post_action = snd_pcm_post_drain_init
1338};
1339
1340struct drain_rec {
1341 snd_pcm_substream_t *substream;
1342 wait_queue_t wait;
1343 snd_pcm_uframes_t stop_threshold;
1344};
1345
1346static int snd_pcm_drop(snd_pcm_substream_t *substream);
1347
1348/*
1349 * Drain the stream(s).
1350 * When the substream is linked, sync until the draining of all playback streams
1351 * is finished.
1352 * After this call, all streams are supposed to be either SETUP or DRAINING
1353 * (capture only) state.
1354 */
1355static int snd_pcm_drain(snd_pcm_substream_t *substream)
1356{
1357 snd_card_t *card;
1358 snd_pcm_runtime_t *runtime;
1359 struct list_head *pos;
1360 int result = 0;
1361 int i, num_drecs;
1362 struct drain_rec *drec, drec_tmp, *d;
1363
1364 snd_assert(substream != NULL, return -ENXIO);
1365 card = substream->pcm->card;
1366 runtime = substream->runtime;
1367
1368 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1369 return -EBADFD;
1370
1371 down_read(&snd_pcm_link_rwsem);
1372 snd_power_lock(card);
1373 if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1374 result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
1375 if (result < 0)
1376 goto _unlock;
1377 }
1378
1379 /* allocate temporary record for drain sync */
1380 if (snd_pcm_stream_linked(substream)) {
1381 drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL);
1382 if (! drec) {
1383 result = -ENOMEM;
1384 goto _unlock;
1385 }
1386 } else
1387 drec = &drec_tmp;
1388
1389 snd_pcm_stream_lock_irq(substream);
1390 /* resume pause */
1391 if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
1392 snd_pcm_pause(substream, 0);
1393
1394 /* pre-start/stop - all running streams are changed to DRAINING state */
1395 result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
1396 if (result < 0)
1397 goto _end;
1398
1399 /* check streams with PLAYBACK & DRAINING */
1400 num_drecs = 0;
1401 snd_pcm_group_for_each(pos, substream) {
1402 snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos);
1403 runtime = s->runtime;
1404 if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) {
1405 runtime->status->state = SNDRV_PCM_STATE_SETUP;
1406 continue;
1407 }
1408 if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1409 d = &drec[num_drecs++];
1410 d->substream = s;
1411 init_waitqueue_entry(&d->wait, current);
1412 add_wait_queue(&runtime->sleep, &d->wait);
1413 /* stop_threshold fixup to avoid endless loop when
1414 * stop_threshold > buffer_size
1415 */
1416 d->stop_threshold = runtime->stop_threshold;
1417 if (runtime->stop_threshold > runtime->buffer_size)
1418 runtime->stop_threshold = runtime->buffer_size;
1419 }
1420 }
1421
1422 if (! num_drecs)
1423 goto _end;
1424
1425 for (;;) {
1426 long tout;
1427 if (signal_pending(current)) {
1428 result = -ERESTARTSYS;
1429 break;
1430 }
1431 set_current_state(TASK_INTERRUPTIBLE);
1432 snd_pcm_stream_unlock_irq(substream);
1433 snd_power_unlock(card);
1434 tout = schedule_timeout(10 * HZ);
1435 snd_power_lock(card);
1436 snd_pcm_stream_lock_irq(substream);
1437 if (tout == 0) {
1438 if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
1439 result = -ESTRPIPE;
1440 else {
1441 snd_printd("playback drain error (DMA or IRQ trouble?)\n");
1442 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
1443 result = -EIO;
1444 }
1445 break;
1446 }
1447 /* all finished? */
1448 for (i = 0; i < num_drecs; i++) {
1449 runtime = drec[i].substream->runtime;
1450 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING)
1451 break;
1452 }
1453 if (i == num_drecs)
1454 break;
1455 }
1456 for (i = 0; i < num_drecs; i++) {
1457 d = &drec[i];
1458 runtime = d->substream->runtime;
1459 remove_wait_queue(&runtime->sleep, &d->wait);
1460 runtime->stop_threshold = d->stop_threshold;
1461 }
1462
1463 _end:
1464 snd_pcm_stream_unlock_irq(substream);
1465 if (drec != &drec_tmp)
1466 kfree(drec);
1467 _unlock:
1468 snd_power_unlock(card);
1469 up_read(&snd_pcm_link_rwsem);
1470
1471 return result;
1472}
1473
1474/*
1475 * drop ioctl
1476 *
1477 * Immediately put all linked substreams into SETUP state.
1478 */
1479static int snd_pcm_drop(snd_pcm_substream_t *substream)
1480{
1481 snd_pcm_runtime_t *runtime;
1482 snd_card_t *card;
1483 int result = 0;
1484
1485 snd_assert(substream != NULL, return -ENXIO);
1486 runtime = substream->runtime;
1487 card = substream->pcm->card;
1488
1489 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1490 return -EBADFD;
1491
1492 snd_power_lock(card);
1493 if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1494 result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile);
1495 if (result < 0)
1496 goto _unlock;
1497 }
1498
1499 snd_pcm_stream_lock_irq(substream);
1500 /* resume pause */
1501 if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
1502 snd_pcm_pause(substream, 0);
1503
1504 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
1505 /* runtime->control->appl_ptr = runtime->status->hw_ptr; */
1506 snd_pcm_stream_unlock_irq(substream);
1507 _unlock:
1508 snd_power_unlock(card);
1509 return result;
1510}
1511
1512
1513/* WARNING: Don't forget to fput back the file */
1514extern int snd_major;
1515static struct file *snd_pcm_file_fd(int fd)
1516{
1517 struct file *file;
1518 struct inode *inode;
1519 unsigned short minor;
1520 file = fget(fd);
1521 if (!file)
1522 return NULL;
1523 inode = file->f_dentry->d_inode;
1524 if (!S_ISCHR(inode->i_mode) ||
1525 imajor(inode) != snd_major) {
1526 fput(file);
1527 return NULL;
1528 }
1529 minor = iminor(inode);
1530 if (minor >= 256 ||
1531 minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) {
1532 fput(file);
1533 return NULL;
1534 }
1535 return file;
1536}
1537
1538/*
1539 * PCM link handling
1540 */
1541static int snd_pcm_link(snd_pcm_substream_t *substream, int fd)
1542{
1543 int res = 0;
1544 struct file *file;
1545 snd_pcm_file_t *pcm_file;
1546 snd_pcm_substream_t *substream1;
1547
1548 file = snd_pcm_file_fd(fd);
1549 if (!file)
1550 return -EBADFD;
1551 pcm_file = file->private_data;
1552 substream1 = pcm_file->substream;
1553 down_write(&snd_pcm_link_rwsem);
1554 write_lock_irq(&snd_pcm_link_rwlock);
1555 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
1556 substream->runtime->status->state != substream1->runtime->status->state) {
1557 res = -EBADFD;
1558 goto _end;
1559 }
1560 if (snd_pcm_stream_linked(substream1)) {
1561 res = -EALREADY;
1562 goto _end;
1563 }
1564 if (!snd_pcm_stream_linked(substream)) {
1565 substream->group = kmalloc(sizeof(snd_pcm_group_t), GFP_ATOMIC);
1566 if (substream->group == NULL) {
1567 res = -ENOMEM;
1568 goto _end;
1569 }
1570 spin_lock_init(&substream->group->lock);
1571 INIT_LIST_HEAD(&substream->group->substreams);
1572 list_add_tail(&substream->link_list, &substream->group->substreams);
1573 substream->group->count = 1;
1574 }
1575 list_add_tail(&substream1->link_list, &substream->group->substreams);
1576 substream->group->count++;
1577 substream1->group = substream->group;
1578 _end:
1579 write_unlock_irq(&snd_pcm_link_rwlock);
1580 up_write(&snd_pcm_link_rwsem);
1581 fput(file);
1582 return res;
1583}
1584
1585static void relink_to_local(snd_pcm_substream_t *substream)
1586{
1587 substream->group = &substream->self_group;
1588 INIT_LIST_HEAD(&substream->self_group.substreams);
1589 list_add_tail(&substream->link_list, &substream->self_group.substreams);
1590}
1591
1592static int snd_pcm_unlink(snd_pcm_substream_t *substream)
1593{
1594 struct list_head *pos;
1595 int res = 0;
1596
1597 down_write(&snd_pcm_link_rwsem);
1598 write_lock_irq(&snd_pcm_link_rwlock);
1599 if (!snd_pcm_stream_linked(substream)) {
1600 res = -EALREADY;
1601 goto _end;
1602 }
1603 list_del(&substream->link_list);
1604 substream->group->count--;
1605 if (substream->group->count == 1) { /* detach the last stream, too */
1606 snd_pcm_group_for_each(pos, substream) {
1607 relink_to_local(snd_pcm_group_substream_entry(pos));
1608 break;
1609 }
1610 kfree(substream->group);
1611 }
1612 relink_to_local(substream);
1613 _end:
1614 write_unlock_irq(&snd_pcm_link_rwlock);
1615 up_write(&snd_pcm_link_rwsem);
1616 return res;
1617}
1618
1619/*
1620 * hw configurator
1621 */
1622static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params,
1623 snd_pcm_hw_rule_t *rule)
1624{
1625 snd_interval_t t;
1626 snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
1627 hw_param_interval_c(params, rule->deps[1]), &t);
1628 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1629}
1630
1631static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params,
1632 snd_pcm_hw_rule_t *rule)
1633{
1634 snd_interval_t t;
1635 snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
1636 hw_param_interval_c(params, rule->deps[1]), &t);
1637 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1638}
1639
1640static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params,
1641 snd_pcm_hw_rule_t *rule)
1642{
1643 snd_interval_t t;
1644 snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
1645 hw_param_interval_c(params, rule->deps[1]),
1646 (unsigned long) rule->private, &t);
1647 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1648}
1649
1650static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params,
1651 snd_pcm_hw_rule_t *rule)
1652{
1653 snd_interval_t t;
1654 snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
1655 (unsigned long) rule->private,
1656 hw_param_interval_c(params, rule->deps[1]), &t);
1657 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1658}
1659
1660static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params,
1661 snd_pcm_hw_rule_t *rule)
1662{
1663 unsigned int k;
1664 snd_interval_t *i = hw_param_interval(params, rule->deps[0]);
1665 snd_mask_t m;
1666 snd_mask_t *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1667 snd_mask_any(&m);
1668 for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
1669 int bits;
1670 if (! snd_mask_test(mask, k))
1671 continue;
1672 bits = snd_pcm_format_physical_width(k);
1673 if (bits <= 0)
1674 continue; /* ignore invalid formats */
1675 if ((unsigned)bits < i->min || (unsigned)bits > i->max)
1676 snd_mask_reset(&m, k);
1677 }
1678 return snd_mask_refine(mask, &m);
1679}
1680
1681static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params,
1682 snd_pcm_hw_rule_t *rule)
1683{
1684 snd_interval_t t;
1685 unsigned int k;
1686 t.min = UINT_MAX;
1687 t.max = 0;
1688 t.openmin = 0;
1689 t.openmax = 0;
1690 for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
1691 int bits;
1692 if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k))
1693 continue;
1694 bits = snd_pcm_format_physical_width(k);
1695 if (bits <= 0)
1696 continue; /* ignore invalid formats */
1697 if (t.min > (unsigned)bits)
1698 t.min = bits;
1699 if (t.max < (unsigned)bits)
1700 t.max = bits;
1701 }
1702 t.integer = 1;
1703 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1704}
1705
1706#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
1707#error "Change this table"
1708#endif
1709
1710static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
1711 48000, 64000, 88200, 96000, 176400, 192000 };
1712
1713static int snd_pcm_hw_rule_rate(snd_pcm_hw_params_t *params,
1714 snd_pcm_hw_rule_t *rule)
1715{
1716 snd_pcm_hardware_t *hw = rule->private;
1717 return snd_interval_list(hw_param_interval(params, rule->var),
1718 ARRAY_SIZE(rates), rates, hw->rates);
1719}
1720
1721static int snd_pcm_hw_rule_buffer_bytes_max(snd_pcm_hw_params_t *params,
1722 snd_pcm_hw_rule_t *rule)
1723{
1724 snd_interval_t t;
1725 snd_pcm_substream_t *substream = rule->private;
1726 t.min = 0;
1727 t.max = substream->buffer_bytes_max;
1728 t.openmin = 0;
1729 t.openmax = 0;
1730 t.integer = 1;
1731 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
1732}
1733
1734int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream)
1735{
1736 snd_pcm_runtime_t *runtime = substream->runtime;
1737 snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints;
1738 int k, err;
1739
1740 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
1741 snd_mask_any(constrs_mask(constrs, k));
1742 }
1743
1744 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
1745 snd_interval_any(constrs_interval(constrs, k));
1746 }
1747
1748 snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS));
1749 snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE));
1750 snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES));
1751 snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS));
1752 snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS));
1753
1754 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
1755 snd_pcm_hw_rule_format, NULL,
1756 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1757 if (err < 0)
1758 return err;
1759 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
1760 snd_pcm_hw_rule_sample_bits, NULL,
1761 SNDRV_PCM_HW_PARAM_FORMAT,
1762 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1763 if (err < 0)
1764 return err;
1765 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
1766 snd_pcm_hw_rule_div, NULL,
1767 SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
1768 if (err < 0)
1769 return err;
1770 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
1771 snd_pcm_hw_rule_mul, NULL,
1772 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
1773 if (err < 0)
1774 return err;
1775 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
1776 snd_pcm_hw_rule_mulkdiv, (void*) 8,
1777 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
1778 if (err < 0)
1779 return err;
1780 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS,
1781 snd_pcm_hw_rule_mulkdiv, (void*) 8,
1782 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
1783 if (err < 0)
1784 return err;
1785 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
1786 snd_pcm_hw_rule_div, NULL,
1787 SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1788 if (err < 0)
1789 return err;
1790 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
1791 snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
1792 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1);
1793 if (err < 0)
1794 return err;
1795 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
1796 snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
1797 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1);
1798 if (err < 0)
1799 return err;
1800 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS,
1801 snd_pcm_hw_rule_div, NULL,
1802 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
1803 if (err < 0)
1804 return err;
1805 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1806 snd_pcm_hw_rule_div, NULL,
1807 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);
1808 if (err < 0)
1809 return err;
1810 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1811 snd_pcm_hw_rule_mulkdiv, (void*) 8,
1812 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
1813 if (err < 0)
1814 return err;
1815 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1816 snd_pcm_hw_rule_muldivk, (void*) 1000000,
1817 SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);
1818 if (err < 0)
1819 return err;
1820 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1821 snd_pcm_hw_rule_mul, NULL,
1822 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);
1823 if (err < 0)
1824 return err;
1825 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1826 snd_pcm_hw_rule_mulkdiv, (void*) 8,
1827 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
1828 if (err < 0)
1829 return err;
1830 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1831 snd_pcm_hw_rule_muldivk, (void*) 1000000,
1832 SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);
1833 if (err < 0)
1834 return err;
1835 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
1836 snd_pcm_hw_rule_muldivk, (void*) 8,
1837 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
1838 if (err < 0)
1839 return err;
1840 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1841 snd_pcm_hw_rule_muldivk, (void*) 8,
1842 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
1843 if (err < 0)
1844 return err;
1845 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME,
1846 snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
1847 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);
1848 if (err < 0)
1849 return err;
1850 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME,
1851 snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
1852 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);
1853 if (err < 0)
1854 return err;
1855 return 0;
1856}
1857
1858int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream)
1859{
1860 snd_pcm_runtime_t *runtime = substream->runtime;
1861 snd_pcm_hardware_t *hw = &runtime->hw;
1862 int err;
1863 unsigned int mask = 0;
1864
1865 if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
1866 mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
1867 if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
1868 mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
1869 if (hw->info & SNDRV_PCM_INFO_MMAP) {
1870 if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
1871 mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
1872 if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
1873 mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED;
1874 if (hw->info & SNDRV_PCM_INFO_COMPLEX)
1875 mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX;
1876 }
1877 err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);
1878 snd_assert(err >= 0, return -EINVAL);
1879
1880 err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
1881 snd_assert(err >= 0, return -EINVAL);
1882
1883 err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
1884 snd_assert(err >= 0, return -EINVAL);
1885
1886 err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
1887 hw->channels_min, hw->channels_max);
1888 snd_assert(err >= 0, return -EINVAL);
1889
1890 err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
1891 hw->rate_min, hw->rate_max);
1892 snd_assert(err >= 0, return -EINVAL);
1893
1894 err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
1895 hw->period_bytes_min, hw->period_bytes_max);
1896 snd_assert(err >= 0, return -EINVAL);
1897
1898 err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
1899 hw->periods_min, hw->periods_max);
1900 snd_assert(err >= 0, return -EINVAL);
1901
1902 err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1903 hw->period_bytes_min, hw->buffer_bytes_max);
1904 snd_assert(err >= 0, return -EINVAL);
1905
1906 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
1907 snd_pcm_hw_rule_buffer_bytes_max, substream,
1908 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
1909 if (err < 0)
1910 return err;
1911
1912 /* FIXME: remove */
1913 if (runtime->dma_bytes) {
1914 err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
1915 snd_assert(err >= 0, return -EINVAL);
1916 }
1917
1918 if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
1919 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
1920 snd_pcm_hw_rule_rate, hw,
1921 SNDRV_PCM_HW_PARAM_RATE, -1);
1922 if (err < 0)
1923 return err;
1924 }
1925
1926 /* FIXME: this belong to lowlevel */
1927 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME,
1928 1000000 / HZ, 1000000 / HZ);
1929 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
1930
1931 return 0;
1932}
1933
1934static void snd_pcm_add_file(snd_pcm_str_t *str,
1935 snd_pcm_file_t *pcm_file)
1936{
1937 pcm_file->next = str->files;
1938 str->files = pcm_file;
1939}
1940
1941static void snd_pcm_remove_file(snd_pcm_str_t *str,
1942 snd_pcm_file_t *pcm_file)
1943{
1944 snd_pcm_file_t * pcm_file1;
1945 if (str->files == pcm_file) {
1946 str->files = pcm_file->next;
1947 } else {
1948 pcm_file1 = str->files;
1949 while (pcm_file1 && pcm_file1->next != pcm_file)
1950 pcm_file1 = pcm_file1->next;
1951 if (pcm_file1 != NULL)
1952 pcm_file1->next = pcm_file->next;
1953 }
1954}
1955
1956static int snd_pcm_release_file(snd_pcm_file_t * pcm_file)
1957{
1958 snd_pcm_substream_t *substream;
1959 snd_pcm_runtime_t *runtime;
1960 snd_pcm_str_t * str;
1961
1962 snd_assert(pcm_file != NULL, return -ENXIO);
1963 substream = pcm_file->substream;
1964 snd_assert(substream != NULL, return -ENXIO);
1965 runtime = substream->runtime;
1966 str = substream->pstr;
1967 snd_pcm_unlink(substream);
1968 if (substream->open_flag) {
1969 if (substream->ops->hw_free != NULL)
1970 substream->ops->hw_free(substream);
1971 substream->ops->close(substream);
1972 substream->open_flag = 0;
1973 }
1974 substream->ffile = NULL;
1975 snd_pcm_remove_file(str, pcm_file);
1976 snd_pcm_release_substream(substream);
1977 kfree(pcm_file);
1978 return 0;
1979}
1980
1981static int snd_pcm_open_file(struct file *file,
1982 snd_pcm_t *pcm,
1983 int stream,
1984 snd_pcm_file_t **rpcm_file)
1985{
1986 int err = 0;
1987 snd_pcm_file_t *pcm_file;
1988 snd_pcm_substream_t *substream;
1989 snd_pcm_str_t *str;
1990
1991 snd_assert(rpcm_file != NULL, return -EINVAL);
1992 *rpcm_file = NULL;
1993
1994 pcm_file = kcalloc(1, sizeof(*pcm_file), GFP_KERNEL);
1995 if (pcm_file == NULL) {
1996 return -ENOMEM;
1997 }
1998
1999 if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) {
2000 kfree(pcm_file);
2001 return err;
2002 }
2003
2004 str = substream->pstr;
2005 substream->file = pcm_file;
2006 substream->no_mmap_ctrl = 0;
2007
2008 pcm_file->substream = substream;
2009
2010 snd_pcm_add_file(str, pcm_file);
2011
2012 err = snd_pcm_hw_constraints_init(substream);
2013 if (err < 0) {
2014 snd_printd("snd_pcm_hw_constraints_init failed\n");
2015 snd_pcm_release_file(pcm_file);
2016 return err;
2017 }
2018
2019 if ((err = substream->ops->open(substream)) < 0) {
2020 snd_pcm_release_file(pcm_file);
2021 return err;
2022 }
2023 substream->open_flag = 1;
2024
2025 err = snd_pcm_hw_constraints_complete(substream);
2026 if (err < 0) {
2027 snd_printd("snd_pcm_hw_constraints_complete failed\n");
2028 substream->ops->close(substream);
2029 snd_pcm_release_file(pcm_file);
2030 return err;
2031 }
2032
2033 substream->ffile = file;
2034
2035 file->private_data = pcm_file;
2036 *rpcm_file = pcm_file;
2037 return 0;
2038}
2039
2040static int snd_pcm_open(struct inode *inode, struct file *file)
2041{
2042 int cardnum = SNDRV_MINOR_CARD(iminor(inode));
2043 int device = SNDRV_MINOR_DEVICE(iminor(inode));
2044 int err;
2045 snd_pcm_t *pcm;
2046 snd_pcm_file_t *pcm_file;
2047 wait_queue_t wait;
2048
2049 snd_runtime_check(device >= SNDRV_MINOR_PCM_PLAYBACK && device < SNDRV_MINOR_DEVICES, return -ENXIO);
2050 pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)];
2051 if (pcm == NULL) {
2052 err = -ENODEV;
2053 goto __error1;
2054 }
2055 err = snd_card_file_add(pcm->card, file);
2056 if (err < 0)
2057 goto __error1;
2058 if (!try_module_get(pcm->card->module)) {
2059 err = -EFAULT;
2060 goto __error2;
2061 }
2062 init_waitqueue_entry(&wait, current);
2063 add_wait_queue(&pcm->open_wait, &wait);
2064 down(&pcm->open_mutex);
2065 while (1) {
2066 err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file);
2067 if (err >= 0)
2068 break;
2069 if (err == -EAGAIN) {
2070 if (file->f_flags & O_NONBLOCK) {
2071 err = -EBUSY;
2072 break;
2073 }
2074 } else
2075 break;
2076 set_current_state(TASK_INTERRUPTIBLE);
2077 up(&pcm->open_mutex);
2078 schedule();
2079 down(&pcm->open_mutex);
2080 if (signal_pending(current)) {
2081 err = -ERESTARTSYS;
2082 break;
2083 }
2084 }
2085 remove_wait_queue(&pcm->open_wait, &wait);
2086 up(&pcm->open_mutex);
2087 if (err < 0)
2088 goto __error;
2089 return err;
2090
2091 __error:
2092 module_put(pcm->card->module);
2093 __error2:
2094 snd_card_file_remove(pcm->card, file);
2095 __error1:
2096 return err;
2097}
2098
2099static int snd_pcm_release(struct inode *inode, struct file *file)
2100{
2101 snd_pcm_t *pcm;
2102 snd_pcm_substream_t *substream;
2103 snd_pcm_file_t *pcm_file;
2104
2105 pcm_file = file->private_data;
2106 substream = pcm_file->substream;
2107 snd_assert(substream != NULL, return -ENXIO);
2108 snd_assert(!atomic_read(&substream->runtime->mmap_count), );
2109 pcm = substream->pcm;
2110 snd_pcm_drop(substream);
2111 fasync_helper(-1, file, 0, &substream->runtime->fasync);
2112 down(&pcm->open_mutex);
2113 snd_pcm_release_file(pcm_file);
2114 up(&pcm->open_mutex);
2115 wake_up(&pcm->open_wait);
2116 module_put(pcm->card->module);
2117 snd_card_file_remove(pcm->card, file);
2118 return 0;
2119}
2120
2121static snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
2122{
2123 snd_pcm_runtime_t *runtime = substream->runtime;
2124 snd_pcm_sframes_t appl_ptr;
2125 snd_pcm_sframes_t ret;
2126 snd_pcm_sframes_t hw_avail;
2127
2128 if (frames == 0)
2129 return 0;
2130
2131 snd_pcm_stream_lock_irq(substream);
2132 switch (runtime->status->state) {
2133 case SNDRV_PCM_STATE_PREPARED:
2134 break;
2135 case SNDRV_PCM_STATE_DRAINING:
2136 case SNDRV_PCM_STATE_RUNNING:
2137 if (snd_pcm_update_hw_ptr(substream) >= 0)
2138 break;
2139 /* Fall through */
2140 case SNDRV_PCM_STATE_XRUN:
2141 ret = -EPIPE;
2142 goto __end;
2143 default:
2144 ret = -EBADFD;
2145 goto __end;
2146 }
2147
2148 hw_avail = snd_pcm_playback_hw_avail(runtime);
2149 if (hw_avail <= 0) {
2150 ret = 0;
2151 goto __end;
2152 }
2153 if (frames > (snd_pcm_uframes_t)hw_avail)
2154 frames = hw_avail;
2155 else
2156 frames -= frames % runtime->xfer_align;
2157 appl_ptr = runtime->control->appl_ptr - frames;
2158 if (appl_ptr < 0)
2159 appl_ptr += runtime->boundary;
2160 runtime->control->appl_ptr = appl_ptr;
2161 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
2162 runtime->sleep_min)
2163 snd_pcm_tick_prepare(substream);
2164 ret = frames;
2165 __end:
2166 snd_pcm_stream_unlock_irq(substream);
2167 return ret;
2168}
2169
2170static snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
2171{
2172 snd_pcm_runtime_t *runtime = substream->runtime;
2173 snd_pcm_sframes_t appl_ptr;
2174 snd_pcm_sframes_t ret;
2175 snd_pcm_sframes_t hw_avail;
2176
2177 if (frames == 0)
2178 return 0;
2179
2180 snd_pcm_stream_lock_irq(substream);
2181 switch (runtime->status->state) {
2182 case SNDRV_PCM_STATE_PREPARED:
2183 case SNDRV_PCM_STATE_DRAINING:
2184 break;
2185 case SNDRV_PCM_STATE_RUNNING:
2186 if (snd_pcm_update_hw_ptr(substream) >= 0)
2187 break;
2188 /* Fall through */
2189 case SNDRV_PCM_STATE_XRUN:
2190 ret = -EPIPE;
2191 goto __end;
2192 default:
2193 ret = -EBADFD;
2194 goto __end;
2195 }
2196
2197 hw_avail = snd_pcm_capture_hw_avail(runtime);
2198 if (hw_avail <= 0) {
2199 ret = 0;
2200 goto __end;
2201 }
2202 if (frames > (snd_pcm_uframes_t)hw_avail)
2203 frames = hw_avail;
2204 else
2205 frames -= frames % runtime->xfer_align;
2206 appl_ptr = runtime->control->appl_ptr - frames;
2207 if (appl_ptr < 0)
2208 appl_ptr += runtime->boundary;
2209 runtime->control->appl_ptr = appl_ptr;
2210 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
2211 runtime->sleep_min)
2212 snd_pcm_tick_prepare(substream);
2213 ret = frames;
2214 __end:
2215 snd_pcm_stream_unlock_irq(substream);
2216 return ret;
2217}
2218
2219static snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
2220{
2221 snd_pcm_runtime_t *runtime = substream->runtime;
2222 snd_pcm_sframes_t appl_ptr;
2223 snd_pcm_sframes_t ret;
2224 snd_pcm_sframes_t avail;
2225
2226 if (frames == 0)
2227 return 0;
2228
2229 snd_pcm_stream_lock_irq(substream);
2230 switch (runtime->status->state) {
2231 case SNDRV_PCM_STATE_PREPARED:
2232 case SNDRV_PCM_STATE_PAUSED:
2233 break;
2234 case SNDRV_PCM_STATE_DRAINING:
2235 case SNDRV_PCM_STATE_RUNNING:
2236 if (snd_pcm_update_hw_ptr(substream) >= 0)
2237 break;
2238 /* Fall through */
2239 case SNDRV_PCM_STATE_XRUN:
2240 ret = -EPIPE;
2241 goto __end;
2242 default:
2243 ret = -EBADFD;
2244 goto __end;
2245 }
2246
2247 avail = snd_pcm_playback_avail(runtime);
2248 if (avail <= 0) {
2249 ret = 0;
2250 goto __end;
2251 }
2252 if (frames > (snd_pcm_uframes_t)avail)
2253 frames = avail;
2254 else
2255 frames -= frames % runtime->xfer_align;
2256 appl_ptr = runtime->control->appl_ptr + frames;
2257 if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
2258 appl_ptr -= runtime->boundary;
2259 runtime->control->appl_ptr = appl_ptr;
2260 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
2261 runtime->sleep_min)
2262 snd_pcm_tick_prepare(substream);
2263 ret = frames;
2264 __end:
2265 snd_pcm_stream_unlock_irq(substream);
2266 return ret;
2267}
2268
2269static snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames)
2270{
2271 snd_pcm_runtime_t *runtime = substream->runtime;
2272 snd_pcm_sframes_t appl_ptr;
2273 snd_pcm_sframes_t ret;
2274 snd_pcm_sframes_t avail;
2275
2276 if (frames == 0)
2277 return 0;
2278
2279 snd_pcm_stream_lock_irq(substream);
2280 switch (runtime->status->state) {
2281 case SNDRV_PCM_STATE_PREPARED:
2282 case SNDRV_PCM_STATE_DRAINING:
2283 case SNDRV_PCM_STATE_PAUSED:
2284 break;
2285 case SNDRV_PCM_STATE_RUNNING:
2286 if (snd_pcm_update_hw_ptr(substream) >= 0)
2287 break;
2288 /* Fall through */
2289 case SNDRV_PCM_STATE_XRUN:
2290 ret = -EPIPE;
2291 goto __end;
2292 default:
2293 ret = -EBADFD;
2294 goto __end;
2295 }
2296
2297 avail = snd_pcm_capture_avail(runtime);
2298 if (avail <= 0) {
2299 ret = 0;
2300 goto __end;
2301 }
2302 if (frames > (snd_pcm_uframes_t)avail)
2303 frames = avail;
2304 else
2305 frames -= frames % runtime->xfer_align;
2306 appl_ptr = runtime->control->appl_ptr + frames;
2307 if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
2308 appl_ptr -= runtime->boundary;
2309 runtime->control->appl_ptr = appl_ptr;
2310 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING &&
2311 runtime->sleep_min)
2312 snd_pcm_tick_prepare(substream);
2313 ret = frames;
2314 __end:
2315 snd_pcm_stream_unlock_irq(substream);
2316 return ret;
2317}
2318
2319static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
2320{
2321 snd_pcm_runtime_t *runtime = substream->runtime;
2322 int err;
2323
2324 snd_pcm_stream_lock_irq(substream);
2325 switch (runtime->status->state) {
2326 case SNDRV_PCM_STATE_DRAINING:
2327 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2328 goto __badfd;
2329 case SNDRV_PCM_STATE_RUNNING:
2330 if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
2331 break;
2332 /* Fall through */
2333 case SNDRV_PCM_STATE_PREPARED:
2334 case SNDRV_PCM_STATE_SUSPENDED:
2335 err = 0;
2336 break;
2337 case SNDRV_PCM_STATE_XRUN:
2338 err = -EPIPE;
2339 break;
2340 default:
2341 __badfd:
2342 err = -EBADFD;
2343 break;
2344 }
2345 snd_pcm_stream_unlock_irq(substream);
2346 return err;
2347}
2348
2349static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __user *res)
2350{
2351 snd_pcm_runtime_t *runtime = substream->runtime;
2352 int err;
2353 snd_pcm_sframes_t n = 0;
2354
2355 snd_pcm_stream_lock_irq(substream);
2356 switch (runtime->status->state) {
2357 case SNDRV_PCM_STATE_DRAINING:
2358 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2359 goto __badfd;
2360 case SNDRV_PCM_STATE_RUNNING:
2361 if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
2362 break;
2363 /* Fall through */
2364 case SNDRV_PCM_STATE_PREPARED:
2365 case SNDRV_PCM_STATE_SUSPENDED:
2366 err = 0;
2367 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2368 n = snd_pcm_playback_hw_avail(runtime);
2369 else
2370 n = snd_pcm_capture_avail(runtime);
2371 break;
2372 case SNDRV_PCM_STATE_XRUN:
2373 err = -EPIPE;
2374 break;
2375 default:
2376 __badfd:
2377 err = -EBADFD;
2378 break;
2379 }
2380 snd_pcm_stream_unlock_irq(substream);
2381 if (!err)
2382 if (put_user(n, res))
2383 err = -EFAULT;
2384 return err;
2385}
2386
2387static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_sync_ptr __user *_sync_ptr)
2388{
2389 snd_pcm_runtime_t *runtime = substream->runtime;
2390 struct sndrv_pcm_sync_ptr sync_ptr;
2391 volatile struct sndrv_pcm_mmap_status *status;
2392 volatile struct sndrv_pcm_mmap_control *control;
2393 int err;
2394
2395 memset(&sync_ptr, 0, sizeof(sync_ptr));
2396 if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
2397 return -EFAULT;
2398 if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct sndrv_pcm_mmap_control)))
2399 return -EFAULT;
2400 status = runtime->status;
2401 control = runtime->control;
2402 if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
2403 err = snd_pcm_hwsync(substream);
2404 if (err < 0)
2405 return err;
2406 }
2407 snd_pcm_stream_lock_irq(substream);
2408 if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
2409 control->appl_ptr = sync_ptr.c.control.appl_ptr;
2410 else
2411 sync_ptr.c.control.appl_ptr = control->appl_ptr;
2412 if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
2413 control->avail_min = sync_ptr.c.control.avail_min;
2414 else
2415 sync_ptr.c.control.avail_min = control->avail_min;
2416 sync_ptr.s.status.state = status->state;
2417 sync_ptr.s.status.hw_ptr = status->hw_ptr;
2418 sync_ptr.s.status.tstamp = status->tstamp;
2419 sync_ptr.s.status.suspended_state = status->suspended_state;
2420 snd_pcm_stream_unlock_irq(substream);
2421 if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
2422 return -EFAULT;
2423 return 0;
2424}
2425
2426static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
2427 unsigned int cmd, void __user *arg);
2428static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
2429 unsigned int cmd, void __user *arg);
2430
2431static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream,
2432 unsigned int cmd, void __user *arg)
2433{
2434 snd_assert(substream != NULL, return -ENXIO);
2435
2436 switch (cmd) {
2437 case SNDRV_PCM_IOCTL_PVERSION:
2438 return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
2439 case SNDRV_PCM_IOCTL_INFO:
2440 return snd_pcm_info_user(substream, arg);
2441 case SNDRV_PCM_IOCTL_TSTAMP:
2442 {
2443 int xarg;
2444 if (get_user(xarg, (int __user *)arg))
2445 return -EFAULT;
2446 substream->runtime->tstamp_timespec = xarg ? 1 : 0;
2447 return 0;
2448 }
2449 case SNDRV_PCM_IOCTL_HW_REFINE:
2450 return snd_pcm_hw_refine_user(substream, arg);
2451 case SNDRV_PCM_IOCTL_HW_PARAMS:
2452 return snd_pcm_hw_params_user(substream, arg);
2453 case SNDRV_PCM_IOCTL_HW_FREE:
2454 return snd_pcm_hw_free(substream);
2455 case SNDRV_PCM_IOCTL_SW_PARAMS:
2456 return snd_pcm_sw_params_user(substream, arg);
2457 case SNDRV_PCM_IOCTL_STATUS:
2458 return snd_pcm_status_user(substream, arg);
2459 case SNDRV_PCM_IOCTL_CHANNEL_INFO:
2460 return snd_pcm_channel_info_user(substream, arg);
2461 case SNDRV_PCM_IOCTL_PREPARE:
2462 return snd_pcm_prepare(substream);
2463 case SNDRV_PCM_IOCTL_RESET:
2464 return snd_pcm_reset(substream);
2465 case SNDRV_PCM_IOCTL_START:
2466 return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
2467 case SNDRV_PCM_IOCTL_LINK:
2468 return snd_pcm_link(substream, (int)(unsigned long) arg);
2469 case SNDRV_PCM_IOCTL_UNLINK:
2470 return snd_pcm_unlink(substream);
2471 case SNDRV_PCM_IOCTL_RESUME:
2472 return snd_pcm_resume(substream);
2473 case SNDRV_PCM_IOCTL_XRUN:
2474 return snd_pcm_xrun(substream);
2475 case SNDRV_PCM_IOCTL_HWSYNC:
2476 return snd_pcm_hwsync(substream);
2477 case SNDRV_PCM_IOCTL_DELAY:
2478 return snd_pcm_delay(substream, arg);
2479 case SNDRV_PCM_IOCTL_SYNC_PTR:
2480 return snd_pcm_sync_ptr(substream, arg);
2481 case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
2482 return snd_pcm_hw_refine_old_user(substream, arg);
2483 case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
2484 return snd_pcm_hw_params_old_user(substream, arg);
2485 case SNDRV_PCM_IOCTL_DRAIN:
2486 return snd_pcm_drain(substream);
2487 case SNDRV_PCM_IOCTL_DROP:
2488 return snd_pcm_drop(substream);
2489 }
2490 snd_printd("unknown ioctl = 0x%x\n", cmd);
2491 return -ENOTTY;
2492}
2493
2494static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
2495 unsigned int cmd, void __user *arg)
2496{
2497 snd_assert(substream != NULL, return -ENXIO);
2498 snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL);
2499 switch (cmd) {
2500 case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
2501 {
2502 snd_xferi_t xferi;
2503 snd_xferi_t __user *_xferi = arg;
2504 snd_pcm_runtime_t *runtime = substream->runtime;
2505 snd_pcm_sframes_t result;
2506 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2507 return -EBADFD;
2508 if (put_user(0, &_xferi->result))
2509 return -EFAULT;
2510 if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
2511 return -EFAULT;
2512 result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
2513 __put_user(result, &_xferi->result);
2514 return result < 0 ? result : 0;
2515 }
2516 case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
2517 {
2518 snd_xfern_t xfern;
2519 snd_xfern_t __user *_xfern = arg;
2520 snd_pcm_runtime_t *runtime = substream->runtime;
2521 void __user **bufs;
2522 snd_pcm_sframes_t result;
2523 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2524 return -EBADFD;
2525 if (runtime->channels > 128)
2526 return -EINVAL;
2527 if (put_user(0, &_xfern->result))
2528 return -EFAULT;
2529 if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
2530 return -EFAULT;
2531 bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
2532 if (bufs == NULL)
2533 return -ENOMEM;
2534 if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
2535 kfree(bufs);
2536 return -EFAULT;
2537 }
2538 result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
2539 kfree(bufs);
2540 __put_user(result, &_xfern->result);
2541 return result < 0 ? result : 0;
2542 }
2543 case SNDRV_PCM_IOCTL_REWIND:
2544 {
2545 snd_pcm_uframes_t frames;
2546 snd_pcm_uframes_t __user *_frames = arg;
2547 snd_pcm_sframes_t result;
2548 if (get_user(frames, _frames))
2549 return -EFAULT;
2550 if (put_user(0, _frames))
2551 return -EFAULT;
2552 result = snd_pcm_playback_rewind(substream, frames);
2553 __put_user(result, _frames);
2554 return result < 0 ? result : 0;
2555 }
2556 case SNDRV_PCM_IOCTL_FORWARD:
2557 {
2558 snd_pcm_uframes_t frames;
2559 snd_pcm_uframes_t __user *_frames = arg;
2560 snd_pcm_sframes_t result;
2561 if (get_user(frames, _frames))
2562 return -EFAULT;
2563 if (put_user(0, _frames))
2564 return -EFAULT;
2565 result = snd_pcm_playback_forward(substream, frames);
2566 __put_user(result, _frames);
2567 return result < 0 ? result : 0;
2568 }
2569 case SNDRV_PCM_IOCTL_PAUSE:
2570 {
2571 int res;
2572 snd_pcm_stream_lock_irq(substream);
2573 res = snd_pcm_pause(substream, (int)(unsigned long)arg);
2574 snd_pcm_stream_unlock_irq(substream);
2575 return res;
2576 }
2577 }
2578 return snd_pcm_common_ioctl1(substream, cmd, arg);
2579}
2580
2581static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
2582 unsigned int cmd, void __user *arg)
2583{
2584 snd_assert(substream != NULL, return -ENXIO);
2585 snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL);
2586 switch (cmd) {
2587 case SNDRV_PCM_IOCTL_READI_FRAMES:
2588 {
2589 snd_xferi_t xferi;
2590 snd_xferi_t __user *_xferi = arg;
2591 snd_pcm_runtime_t *runtime = substream->runtime;
2592 snd_pcm_sframes_t result;
2593 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2594 return -EBADFD;
2595 if (put_user(0, &_xferi->result))
2596 return -EFAULT;
2597 if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
2598 return -EFAULT;
2599 result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
2600 __put_user(result, &_xferi->result);
2601 return result < 0 ? result : 0;
2602 }
2603 case SNDRV_PCM_IOCTL_READN_FRAMES:
2604 {
2605 snd_xfern_t xfern;
2606 snd_xfern_t __user *_xfern = arg;
2607 snd_pcm_runtime_t *runtime = substream->runtime;
2608 void *bufs;
2609 snd_pcm_sframes_t result;
2610 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2611 return -EBADFD;
2612 if (runtime->channels > 128)
2613 return -EINVAL;
2614 if (put_user(0, &_xfern->result))
2615 return -EFAULT;
2616 if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
2617 return -EFAULT;
2618 bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
2619 if (bufs == NULL)
2620 return -ENOMEM;
2621 if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
2622 kfree(bufs);
2623 return -EFAULT;
2624 }
2625 result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
2626 kfree(bufs);
2627 __put_user(result, &_xfern->result);
2628 return result < 0 ? result : 0;
2629 }
2630 case SNDRV_PCM_IOCTL_REWIND:
2631 {
2632 snd_pcm_uframes_t frames;
2633 snd_pcm_uframes_t __user *_frames = arg;
2634 snd_pcm_sframes_t result;
2635 if (get_user(frames, _frames))
2636 return -EFAULT;
2637 if (put_user(0, _frames))
2638 return -EFAULT;
2639 result = snd_pcm_capture_rewind(substream, frames);
2640 __put_user(result, _frames);
2641 return result < 0 ? result : 0;
2642 }
2643 case SNDRV_PCM_IOCTL_FORWARD:
2644 {
2645 snd_pcm_uframes_t frames;
2646 snd_pcm_uframes_t __user *_frames = arg;
2647 snd_pcm_sframes_t result;
2648 if (get_user(frames, _frames))
2649 return -EFAULT;
2650 if (put_user(0, _frames))
2651 return -EFAULT;
2652 result = snd_pcm_capture_forward(substream, frames);
2653 __put_user(result, _frames);
2654 return result < 0 ? result : 0;
2655 }
2656 }
2657 return snd_pcm_common_ioctl1(substream, cmd, arg);
2658}
2659
2660static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2661{
2662 snd_pcm_file_t *pcm_file;
2663
2664 pcm_file = file->private_data;
2665
2666 if (((cmd >> 8) & 0xff) != 'A')
2667 return -ENOTTY;
2668
2669 return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
2670}
2671
2672static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2673{
2674 snd_pcm_file_t *pcm_file;
2675
2676 pcm_file = file->private_data;
2677
2678 if (((cmd >> 8) & 0xff) != 'A')
2679 return -ENOTTY;
2680
2681 return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg);
2682}
2683
2684int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream,
2685 unsigned int cmd, void *arg)
2686{
2687 mm_segment_t fs;
2688 int result;
2689
2690 fs = snd_enter_user();
2691 result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg);
2692 snd_leave_user(fs);
2693 return result;
2694}
2695
2696int snd_pcm_kernel_capture_ioctl(snd_pcm_substream_t *substream,
2697 unsigned int cmd, void *arg)
2698{
2699 mm_segment_t fs;
2700 int result;
2701
2702 fs = snd_enter_user();
2703 result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg);
2704 snd_leave_user(fs);
2705 return result;
2706}
2707
2708int snd_pcm_kernel_ioctl(snd_pcm_substream_t *substream,
2709 unsigned int cmd, void *arg)
2710{
2711 switch (substream->stream) {
2712 case SNDRV_PCM_STREAM_PLAYBACK:
2713 return snd_pcm_kernel_playback_ioctl(substream, cmd, arg);
2714 case SNDRV_PCM_STREAM_CAPTURE:
2715 return snd_pcm_kernel_capture_ioctl(substream, cmd, arg);
2716 default:
2717 return -EINVAL;
2718 }
2719}
2720
2721static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, loff_t * offset)
2722{
2723 snd_pcm_file_t *pcm_file;
2724 snd_pcm_substream_t *substream;
2725 snd_pcm_runtime_t *runtime;
2726 snd_pcm_sframes_t result;
2727
2728 pcm_file = file->private_data;
2729 substream = pcm_file->substream;
2730 snd_assert(substream != NULL, return -ENXIO);
2731 runtime = substream->runtime;
2732 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2733 return -EBADFD;
2734 if (!frame_aligned(runtime, count))
2735 return -EINVAL;
2736 count = bytes_to_frames(runtime, count);
2737 result = snd_pcm_lib_read(substream, buf, count);
2738 if (result > 0)
2739 result = frames_to_bytes(runtime, result);
2740 return result;
2741}
2742
2743static ssize_t snd_pcm_write(struct file *file, const char __user *buf, size_t count, loff_t * offset)
2744{
2745 snd_pcm_file_t *pcm_file;
2746 snd_pcm_substream_t *substream;
2747 snd_pcm_runtime_t *runtime;
2748 snd_pcm_sframes_t result;
2749
2750 pcm_file = file->private_data;
2751 substream = pcm_file->substream;
2752 snd_assert(substream != NULL, result = -ENXIO; goto end);
2753 runtime = substream->runtime;
2754 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
2755 result = -EBADFD;
2756 goto end;
2757 }
2758 if (!frame_aligned(runtime, count)) {
2759 result = -EINVAL;
2760 goto end;
2761 }
2762 count = bytes_to_frames(runtime, count);
2763 result = snd_pcm_lib_write(substream, buf, count);
2764 if (result > 0)
2765 result = frames_to_bytes(runtime, result);
2766 end:
2767 return result;
2768}
2769
2770static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
2771 unsigned long count, loff_t * offset)
2772
2773{
2774 snd_pcm_file_t *pcm_file;
2775 snd_pcm_substream_t *substream;
2776 snd_pcm_runtime_t *runtime;
2777 snd_pcm_sframes_t result;
2778 unsigned long i;
2779 void __user **bufs;
2780 snd_pcm_uframes_t frames;
2781
2782 pcm_file = file->private_data;
2783 substream = pcm_file->substream;
2784 snd_assert(substream != NULL, return -ENXIO);
2785 runtime = substream->runtime;
2786 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2787 return -EBADFD;
2788 if (count > 1024 || count != runtime->channels)
2789 return -EINVAL;
2790 if (!frame_aligned(runtime, _vector->iov_len))
2791 return -EINVAL;
2792 frames = bytes_to_samples(runtime, _vector->iov_len);
2793 bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
2794 if (bufs == NULL)
2795 return -ENOMEM;
2796 for (i = 0; i < count; ++i)
2797 bufs[i] = _vector[i].iov_base;
2798 result = snd_pcm_lib_readv(substream, bufs, frames);
2799 if (result > 0)
2800 result = frames_to_bytes(runtime, result);
2801 kfree(bufs);
2802 return result;
2803}
2804
2805static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector,
2806 unsigned long count, loff_t * offset)
2807{
2808 snd_pcm_file_t *pcm_file;
2809 snd_pcm_substream_t *substream;
2810 snd_pcm_runtime_t *runtime;
2811 snd_pcm_sframes_t result;
2812 unsigned long i;
2813 void __user **bufs;
2814 snd_pcm_uframes_t frames;
2815
2816 pcm_file = file->private_data;
2817 substream = pcm_file->substream;
2818 snd_assert(substream != NULL, result = -ENXIO; goto end);
2819 runtime = substream->runtime;
2820 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
2821 result = -EBADFD;
2822 goto end;
2823 }
2824 if (count > 128 || count != runtime->channels ||
2825 !frame_aligned(runtime, _vector->iov_len)) {
2826 result = -EINVAL;
2827 goto end;
2828 }
2829 frames = bytes_to_samples(runtime, _vector->iov_len);
2830 bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
2831 if (bufs == NULL)
2832 return -ENOMEM;
2833 for (i = 0; i < count; ++i)
2834 bufs[i] = _vector[i].iov_base;
2835 result = snd_pcm_lib_writev(substream, bufs, frames);
2836 if (result > 0)
2837 result = frames_to_bytes(runtime, result);
2838 kfree(bufs);
2839 end:
2840 return result;
2841}
2842
2843static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait)
2844{
2845 snd_pcm_file_t *pcm_file;
2846 snd_pcm_substream_t *substream;
2847 snd_pcm_runtime_t *runtime;
2848 unsigned int mask;
2849 snd_pcm_uframes_t avail;
2850
2851 pcm_file = file->private_data;
2852
2853 substream = pcm_file->substream;
2854 snd_assert(substream != NULL, return -ENXIO);
2855 runtime = substream->runtime;
2856
2857 poll_wait(file, &runtime->sleep, wait);
2858
2859 snd_pcm_stream_lock_irq(substream);
2860 avail = snd_pcm_playback_avail(runtime);
2861 switch (runtime->status->state) {
2862 case SNDRV_PCM_STATE_RUNNING:
2863 case SNDRV_PCM_STATE_PREPARED:
2864 case SNDRV_PCM_STATE_PAUSED:
2865 if (avail >= runtime->control->avail_min) {
2866 mask = POLLOUT | POLLWRNORM;
2867 break;
2868 }
2869 /* Fall through */
2870 case SNDRV_PCM_STATE_DRAINING:
2871 mask = 0;
2872 break;
2873 default:
2874 mask = POLLOUT | POLLWRNORM | POLLERR;
2875 break;
2876 }
2877 snd_pcm_stream_unlock_irq(substream);
2878 return mask;
2879}
2880
2881static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
2882{
2883 snd_pcm_file_t *pcm_file;
2884 snd_pcm_substream_t *substream;
2885 snd_pcm_runtime_t *runtime;
2886 unsigned int mask;
2887 snd_pcm_uframes_t avail;
2888
2889 pcm_file = file->private_data;
2890
2891 substream = pcm_file->substream;
2892 snd_assert(substream != NULL, return -ENXIO);
2893 runtime = substream->runtime;
2894
2895 poll_wait(file, &runtime->sleep, wait);
2896
2897 snd_pcm_stream_lock_irq(substream);
2898 avail = snd_pcm_capture_avail(runtime);
2899 switch (runtime->status->state) {
2900 case SNDRV_PCM_STATE_RUNNING:
2901 case SNDRV_PCM_STATE_PREPARED:
2902 case SNDRV_PCM_STATE_PAUSED:
2903 if (avail >= runtime->control->avail_min) {
2904 mask = POLLIN | POLLRDNORM;
2905 break;
2906 }
2907 mask = 0;
2908 break;
2909 case SNDRV_PCM_STATE_DRAINING:
2910 if (avail > 0) {
2911 mask = POLLIN | POLLRDNORM;
2912 break;
2913 }
2914 /* Fall through */
2915 default:
2916 mask = POLLIN | POLLRDNORM | POLLERR;
2917 break;
2918 }
2919 snd_pcm_stream_unlock_irq(substream);
2920 return mask;
2921}
2922
2923/*
2924 * mmap support
2925 */
2926
2927/*
2928 * Only on coherent architectures, we can mmap the status and the control records
2929 * for effcient data transfer. On others, we have to use HWSYNC ioctl...
2930 */
2931#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA)
2932/*
2933 * mmap status record
2934 */
2935static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, unsigned long address, int *type)
2936{
2937 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
2938 snd_pcm_runtime_t *runtime;
2939 struct page * page;
2940
2941 if (substream == NULL)
2942 return NOPAGE_OOM;
2943 runtime = substream->runtime;
2944 page = virt_to_page(runtime->status);
2945 if (!PageReserved(page))
2946 get_page(page);
2947 if (type)
2948 *type = VM_FAULT_MINOR;
2949 return page;
2950}
2951
2952static struct vm_operations_struct snd_pcm_vm_ops_status =
2953{
2954 .nopage = snd_pcm_mmap_status_nopage,
2955};
2956
2957static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
2958 struct vm_area_struct *area)
2959{
2960 snd_pcm_runtime_t *runtime;
2961 long size;
2962 if (!(area->vm_flags & VM_READ))
2963 return -EINVAL;
2964 runtime = substream->runtime;
2965 snd_assert(runtime != NULL, return -EAGAIN);
2966 size = area->vm_end - area->vm_start;
2967 if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t)))
2968 return -EINVAL;
2969 area->vm_ops = &snd_pcm_vm_ops_status;
2970 area->vm_private_data = substream;
2971 area->vm_flags |= VM_RESERVED;
2972 return 0;
2973}
2974
2975/*
2976 * mmap control record
2977 */
2978static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, unsigned long address, int *type)
2979{
2980 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
2981 snd_pcm_runtime_t *runtime;
2982 struct page * page;
2983
2984 if (substream == NULL)
2985 return NOPAGE_OOM;
2986 runtime = substream->runtime;
2987 page = virt_to_page(runtime->control);
2988 if (!PageReserved(page))
2989 get_page(page);
2990 if (type)
2991 *type = VM_FAULT_MINOR;
2992 return page;
2993}
2994
2995static struct vm_operations_struct snd_pcm_vm_ops_control =
2996{
2997 .nopage = snd_pcm_mmap_control_nopage,
2998};
2999
3000static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file,
3001 struct vm_area_struct *area)
3002{
3003 snd_pcm_runtime_t *runtime;
3004 long size;
3005 if (!(area->vm_flags & VM_READ))
3006 return -EINVAL;
3007 runtime = substream->runtime;
3008 snd_assert(runtime != NULL, return -EAGAIN);
3009 size = area->vm_end - area->vm_start;
3010 if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t)))
3011 return -EINVAL;
3012 area->vm_ops = &snd_pcm_vm_ops_control;
3013 area->vm_private_data = substream;
3014 area->vm_flags |= VM_RESERVED;
3015 return 0;
3016}
3017#else /* ! coherent mmap */
3018/*
3019 * don't support mmap for status and control records.
3020 */
3021static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file,
3022 struct vm_area_struct *area)
3023{
3024 return -ENXIO;
3025}
3026static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file,
3027 struct vm_area_struct *area)
3028{
3029 return -ENXIO;
3030}
3031#endif /* coherent mmap */
3032
3033/*
3034 * nopage callback for mmapping a RAM page
3035 */
3036static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int *type)
3037{
3038 snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data;
3039 snd_pcm_runtime_t *runtime;
3040 unsigned long offset;
3041 struct page * page;
3042 void *vaddr;
3043 size_t dma_bytes;
3044
3045 if (substream == NULL)
3046 return NOPAGE_OOM;
3047 runtime = substream->runtime;
3048 offset = area->vm_pgoff << PAGE_SHIFT;
3049 offset += address - area->vm_start;
3050 snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
3051 dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
3052 if (offset > dma_bytes - PAGE_SIZE)
3053 return NOPAGE_SIGBUS;
3054 if (substream->ops->page) {
3055 page = substream->ops->page(substream, offset);
3056 if (! page)
3057 return NOPAGE_OOM;
3058 } else {
3059 vaddr = runtime->dma_area + offset;
3060 page = virt_to_page(vaddr);
3061 }
3062 if (!PageReserved(page))
3063 get_page(page);
3064 if (type)
3065 *type = VM_FAULT_MINOR;
3066 return page;
3067}
3068
3069static struct vm_operations_struct snd_pcm_vm_ops_data =
3070{
3071 .open = snd_pcm_mmap_data_open,
3072 .close = snd_pcm_mmap_data_close,
3073 .nopage = snd_pcm_mmap_data_nopage,
3074};
3075
3076/*
3077 * mmap the DMA buffer on RAM
3078 */
3079static int snd_pcm_default_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *area)
3080{
3081 area->vm_ops = &snd_pcm_vm_ops_data;
3082 area->vm_private_data = substream;
3083 area->vm_flags |= VM_RESERVED;
3084 atomic_inc(&substream->runtime->mmap_count);
3085 return 0;
3086}
3087
3088/*
3089 * mmap the DMA buffer on I/O memory area
3090 */
3091#if SNDRV_PCM_INFO_MMAP_IOMEM
3092static struct vm_operations_struct snd_pcm_vm_ops_data_mmio =
3093{
3094 .open = snd_pcm_mmap_data_open,
3095 .close = snd_pcm_mmap_data_close,
3096};
3097
3098int snd_pcm_lib_mmap_iomem(snd_pcm_substream_t *substream, struct vm_area_struct *area)
3099{
3100 long size;
3101 unsigned long offset;
3102
3103#ifdef pgprot_noncached
3104 area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
3105#endif
3106 area->vm_ops = &snd_pcm_vm_ops_data_mmio;
3107 area->vm_private_data = substream;
3108 area->vm_flags |= VM_IO;
3109 size = area->vm_end - area->vm_start;
3110 offset = area->vm_pgoff << PAGE_SHIFT;
3111 if (io_remap_pfn_range(area, area->vm_start,
3112 (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
3113 size, area->vm_page_prot))
3114 return -EAGAIN;
3115 atomic_inc(&substream->runtime->mmap_count);
3116 return 0;
3117}
3118#endif /* SNDRV_PCM_INFO_MMAP */
3119
3120/*
3121 * mmap DMA buffer
3122 */
3123int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file,
3124 struct vm_area_struct *area)
3125{
3126 snd_pcm_runtime_t *runtime;
3127 long size;
3128 unsigned long offset;
3129 size_t dma_bytes;
3130
3131 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
3132 if (!(area->vm_flags & (VM_WRITE|VM_READ)))
3133 return -EINVAL;
3134 } else {
3135 if (!(area->vm_flags & VM_READ))
3136 return -EINVAL;
3137 }
3138 runtime = substream->runtime;
3139 snd_assert(runtime != NULL, return -EAGAIN);
3140 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
3141 return -EBADFD;
3142 if (!(runtime->info & SNDRV_PCM_INFO_MMAP))
3143 return -ENXIO;
3144 if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
3145 runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
3146 return -EINVAL;
3147 size = area->vm_end - area->vm_start;
3148 offset = area->vm_pgoff << PAGE_SHIFT;
3149 dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
3150 if ((size_t)size > dma_bytes)
3151 return -EINVAL;
3152 if (offset > dma_bytes - size)
3153 return -EINVAL;
3154
3155 if (substream->ops->mmap)
3156 return substream->ops->mmap(substream, area);
3157 else
3158 return snd_pcm_default_mmap(substream, area);
3159}
3160
3161static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
3162{
3163 snd_pcm_file_t * pcm_file;
3164 snd_pcm_substream_t *substream;
3165 unsigned long offset;
3166
3167 pcm_file = file->private_data;
3168 substream = pcm_file->substream;
3169 snd_assert(substream != NULL, return -ENXIO);
3170
3171 offset = area->vm_pgoff << PAGE_SHIFT;
3172 switch (offset) {
3173 case SNDRV_PCM_MMAP_OFFSET_STATUS:
3174 if (substream->no_mmap_ctrl)
3175 return -ENXIO;
3176 return snd_pcm_mmap_status(substream, file, area);
3177 case SNDRV_PCM_MMAP_OFFSET_CONTROL:
3178 if (substream->no_mmap_ctrl)
3179 return -ENXIO;
3180 return snd_pcm_mmap_control(substream, file, area);
3181 default:
3182 return snd_pcm_mmap_data(substream, file, area);
3183 }
3184 return 0;
3185}
3186
3187static int snd_pcm_fasync(int fd, struct file * file, int on)
3188{
3189 snd_pcm_file_t * pcm_file;
3190 snd_pcm_substream_t *substream;
3191 snd_pcm_runtime_t *runtime;
3192 int err;
3193
3194 pcm_file = file->private_data;
3195 substream = pcm_file->substream;
3196 snd_assert(substream != NULL, return -ENXIO);
3197 runtime = substream->runtime;
3198
3199 err = fasync_helper(fd, file, on, &runtime->fasync);
3200 if (err < 0)
3201 return err;
3202 return 0;
3203}
3204
3205/*
3206 * ioctl32 compat
3207 */
3208#ifdef CONFIG_COMPAT
3209#include "pcm_compat.c"
3210#else
3211#define snd_pcm_ioctl_compat NULL
3212#endif
3213
3214/*
3215 * To be removed helpers to keep binary compatibility
3216 */
3217
3218#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
3219#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))
3220
3221static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old *oparams)
3222{
3223 unsigned int i;
3224
3225 memset(params, 0, sizeof(*params));
3226 params->flags = oparams->flags;
3227 for (i = 0; i < ARRAY_SIZE(oparams->masks); i++)
3228 params->masks[i].bits[0] = oparams->masks[i];
3229 memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
3230 params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
3231 params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
3232 params->info = oparams->info;
3233 params->msbits = oparams->msbits;
3234 params->rate_num = oparams->rate_num;
3235 params->rate_den = oparams->rate_den;
3236 params->fifo_size = oparams->fifo_size;
3237}
3238
3239static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams, snd_pcm_hw_params_t *params)
3240{
3241 unsigned int i;
3242
3243 memset(oparams, 0, sizeof(*oparams));
3244 oparams->flags = params->flags;
3245 for (i = 0; i < ARRAY_SIZE(oparams->masks); i++)
3246 oparams->masks[i] = params->masks[i].bits[0];
3247 memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
3248 oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
3249 oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
3250 oparams->info = params->info;
3251 oparams->msbits = params->msbits;
3252 oparams->rate_num = params->rate_num;
3253 oparams->rate_den = params->rate_den;
3254 oparams->fifo_size = params->fifo_size;
3255}
3256
3257static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams)
3258{
3259 snd_pcm_hw_params_t *params;
3260 struct sndrv_pcm_hw_params_old *oparams = NULL;
3261 int err;
3262
3263 params = kmalloc(sizeof(*params), GFP_KERNEL);
3264 if (!params) {
3265 err = -ENOMEM;
3266 goto out;
3267 }
3268 oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
3269 if (!oparams) {
3270 err = -ENOMEM;
3271 goto out;
3272 }
3273
3274 if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
3275 err = -EFAULT;
3276 goto out;
3277 }
3278 snd_pcm_hw_convert_from_old_params(params, oparams);
3279 err = snd_pcm_hw_refine(substream, params);
3280 snd_pcm_hw_convert_to_old_params(oparams, params);
3281 if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
3282 if (!err)
3283 err = -EFAULT;
3284 }
3285out:
3286 kfree(params);
3287 kfree(oparams);
3288 return err;
3289}
3290
3291static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams)
3292{
3293 snd_pcm_hw_params_t *params;
3294 struct sndrv_pcm_hw_params_old *oparams = NULL;
3295 int err;
3296
3297 params = kmalloc(sizeof(*params), GFP_KERNEL);
3298 if (!params) {
3299 err = -ENOMEM;
3300 goto out;
3301 }
3302 oparams = kmalloc(sizeof(*oparams), GFP_KERNEL);
3303 if (!oparams) {
3304 err = -ENOMEM;
3305 goto out;
3306 }
3307 if (copy_from_user(oparams, _oparams, sizeof(*oparams))) {
3308 err = -EFAULT;
3309 goto out;
3310 }
3311 snd_pcm_hw_convert_from_old_params(params, oparams);
3312 err = snd_pcm_hw_params(substream, params);
3313 snd_pcm_hw_convert_to_old_params(oparams, params);
3314 if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
3315 if (!err)
3316 err = -EFAULT;
3317 }
3318out:
3319 kfree(params);
3320 kfree(oparams);
3321 return err;
3322}
3323
3324/*
3325 * Register section
3326 */
3327
3328static struct file_operations snd_pcm_f_ops_playback = {
3329 .owner = THIS_MODULE,
3330 .write = snd_pcm_write,
3331 .writev = snd_pcm_writev,
3332 .open = snd_pcm_open,
3333 .release = snd_pcm_release,
3334 .poll = snd_pcm_playback_poll,
3335 .unlocked_ioctl = snd_pcm_playback_ioctl,
3336 .compat_ioctl = snd_pcm_ioctl_compat,
3337 .mmap = snd_pcm_mmap,
3338 .fasync = snd_pcm_fasync,
3339};
3340
3341static struct file_operations snd_pcm_f_ops_capture = {
3342 .owner = THIS_MODULE,
3343 .read = snd_pcm_read,
3344 .readv = snd_pcm_readv,
3345 .open = snd_pcm_open,
3346 .release = snd_pcm_release,
3347 .poll = snd_pcm_capture_poll,
3348 .unlocked_ioctl = snd_pcm_capture_ioctl,
3349 .compat_ioctl = snd_pcm_ioctl_compat,
3350 .mmap = snd_pcm_mmap,
3351 .fasync = snd_pcm_fasync,
3352};
3353
3354snd_minor_t snd_pcm_reg[2] =
3355{
3356 {
3357 .comment = "digital audio playback",
3358 .f_ops = &snd_pcm_f_ops_playback,
3359 },
3360 {
3361 .comment = "digital audio capture",
3362 .f_ops = &snd_pcm_f_ops_capture,
3363 }
3364};
diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
new file mode 100644
index 000000000000..884eaea31fec
--- /dev/null
+++ b/sound/core/pcm_timer.c
@@ -0,0 +1,161 @@
1/*
2 * Digital Audio (PCM) abstract layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/time.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/timer.h>
27
28/*
29 * Timer functions
30 */
31
32/* Greatest common divisor */
33static unsigned long gcd(unsigned long a, unsigned long b)
34{
35 unsigned long r;
36 if (a < b) {
37 r = a;
38 a = b;
39 b = r;
40 }
41 while ((r = a % b) != 0) {
42 a = b;
43 b = r;
44 }
45 return b;
46}
47
48void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
49{
50 unsigned long rate, mult, fsize, l, post;
51 snd_pcm_runtime_t *runtime = substream->runtime;
52
53 mult = 1000000000;
54 rate = runtime->rate;
55 snd_assert(rate != 0, return);
56 l = gcd(mult, rate);
57 mult /= l;
58 rate /= l;
59 fsize = runtime->period_size;
60 snd_assert(fsize != 0, return);
61 l = gcd(rate, fsize);
62 rate /= l;
63 fsize /= l;
64 post = 1;
65 while ((mult * fsize) / fsize != mult) {
66 mult /= 2;
67 post *= 2;
68 }
69 if (rate == 0) {
70 snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
71 runtime->timer_resolution = -1;
72 return;
73 }
74 runtime->timer_resolution = (mult * fsize / rate) * post;
75}
76
77static unsigned long snd_pcm_timer_resolution(snd_timer_t * timer)
78{
79 snd_pcm_substream_t * substream;
80
81 substream = timer->private_data;
82 return substream->runtime ? substream->runtime->timer_resolution : 0;
83}
84
85static int snd_pcm_timer_start(snd_timer_t * timer)
86{
87 unsigned long flags;
88 snd_pcm_substream_t * substream;
89
90 substream = snd_timer_chip(timer);
91 spin_lock_irqsave(&substream->timer_lock, flags);
92 substream->timer_running = 1;
93 spin_unlock_irqrestore(&substream->timer_lock, flags);
94 return 0;
95}
96
97static int snd_pcm_timer_stop(snd_timer_t * timer)
98{
99 unsigned long flags;
100 snd_pcm_substream_t * substream;
101
102 substream = snd_timer_chip(timer);
103 spin_lock_irqsave(&substream->timer_lock, flags);
104 substream->timer_running = 0;
105 spin_unlock_irqrestore(&substream->timer_lock, flags);
106 return 0;
107}
108
109static struct _snd_timer_hardware snd_pcm_timer =
110{
111 .flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_SLAVE,
112 .resolution = 0,
113 .ticks = 1,
114 .c_resolution = snd_pcm_timer_resolution,
115 .start = snd_pcm_timer_start,
116 .stop = snd_pcm_timer_stop,
117};
118
119/*
120 * Init functions
121 */
122
123static void snd_pcm_timer_free(snd_timer_t *timer)
124{
125 snd_pcm_substream_t *substream = timer->private_data;
126 substream->timer = NULL;
127}
128
129void snd_pcm_timer_init(snd_pcm_substream_t *substream)
130{
131 snd_timer_id_t tid;
132 snd_timer_t *timer;
133
134 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
135 tid.dev_class = SNDRV_TIMER_CLASS_PCM;
136 tid.card = substream->pcm->card->number;
137 tid.device = substream->pcm->device;
138 tid.subdevice = (substream->number << 1) | (substream->stream & 1);
139 if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0)
140 return;
141 sprintf(timer->name, "PCM %s %i-%i-%i",
142 substream->stream == SNDRV_PCM_STREAM_CAPTURE ?
143 "capture" : "playback",
144 tid.card, tid.device, tid.subdevice);
145 timer->hw = snd_pcm_timer;
146 if (snd_device_register(timer->card, timer) < 0) {
147 snd_device_free(timer->card, timer);
148 return;
149 }
150 timer->private_data = substream;
151 timer->private_free = snd_pcm_timer_free;
152 substream->timer = timer;
153}
154
155void snd_pcm_timer_done(snd_pcm_substream_t *substream)
156{
157 if (substream->timer) {
158 snd_device_free(substream->pcm->card, substream->timer);
159 substream->timer = NULL;
160 }
161}
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
new file mode 100644
index 000000000000..edba4118271c
--- /dev/null
+++ b/sound/core/rawmidi.c
@@ -0,0 +1,1680 @@
1/*
2 * Abstract layer for MIDI v1.0 stream
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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 <sound/core.h>
24#include <linux/major.h>
25#include <linux/init.h>
26#include <linux/smp_lock.h>
27#include <linux/sched.h>
28#include <linux/slab.h>
29#include <linux/time.h>
30#include <linux/wait.h>
31#include <linux/moduleparam.h>
32#include <linux/delay.h>
33#include <linux/wait.h>
34#include <sound/rawmidi.h>
35#include <sound/info.h>
36#include <sound/control.h>
37#include <sound/minors.h>
38#include <sound/initval.h>
39
40MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
41MODULE_DESCRIPTION("Midlevel RawMidi code for ALSA.");
42MODULE_LICENSE("GPL");
43
44#ifdef CONFIG_SND_OSSEMUL
45static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
46static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
47module_param_array(midi_map, int, NULL, 0444);
48MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
49module_param_array(amidi_map, int, NULL, 0444);
50MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
51#endif /* CONFIG_SND_OSSEMUL */
52
53static int snd_rawmidi_free(snd_rawmidi_t *rawmidi);
54static int snd_rawmidi_dev_free(snd_device_t *device);
55static int snd_rawmidi_dev_register(snd_device_t *device);
56static int snd_rawmidi_dev_disconnect(snd_device_t *device);
57static int snd_rawmidi_dev_unregister(snd_device_t *device);
58
59static snd_rawmidi_t *snd_rawmidi_devices[SNDRV_CARDS * SNDRV_RAWMIDI_DEVICES];
60
61static DECLARE_MUTEX(register_mutex);
62
63static inline unsigned short snd_rawmidi_file_flags(struct file *file)
64{
65 switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
66 case FMODE_WRITE:
67 return SNDRV_RAWMIDI_LFLG_OUTPUT;
68 case FMODE_READ:
69 return SNDRV_RAWMIDI_LFLG_INPUT;
70 default:
71 return SNDRV_RAWMIDI_LFLG_OPEN;
72 }
73}
74
75static inline int snd_rawmidi_ready(snd_rawmidi_substream_t * substream)
76{
77 snd_rawmidi_runtime_t *runtime = substream->runtime;
78 return runtime->avail >= runtime->avail_min;
79}
80
81static inline int snd_rawmidi_ready_append(snd_rawmidi_substream_t * substream, size_t count)
82{
83 snd_rawmidi_runtime_t *runtime = substream->runtime;
84 return runtime->avail >= runtime->avail_min &&
85 (!substream->append || runtime->avail >= count);
86}
87
88static void snd_rawmidi_input_event_tasklet(unsigned long data)
89{
90 snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
91 substream->runtime->event(substream);
92}
93
94static void snd_rawmidi_output_trigger_tasklet(unsigned long data)
95{
96 snd_rawmidi_substream_t *substream = (snd_rawmidi_substream_t *)data;
97 substream->ops->trigger(substream, 1);
98}
99
100static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream)
101{
102 snd_rawmidi_runtime_t *runtime;
103
104 if ((runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL)) == NULL)
105 return -ENOMEM;
106 spin_lock_init(&runtime->lock);
107 init_waitqueue_head(&runtime->sleep);
108 if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
109 tasklet_init(&runtime->tasklet,
110 snd_rawmidi_input_event_tasklet,
111 (unsigned long)substream);
112 else
113 tasklet_init(&runtime->tasklet,
114 snd_rawmidi_output_trigger_tasklet,
115 (unsigned long)substream);
116 runtime->event = NULL;
117 runtime->buffer_size = PAGE_SIZE;
118 runtime->avail_min = 1;
119 if (substream->stream == SNDRV_RAWMIDI_STREAM_INPUT)
120 runtime->avail = 0;
121 else
122 runtime->avail = runtime->buffer_size;
123 if ((runtime->buffer = kmalloc(runtime->buffer_size, GFP_KERNEL)) == NULL) {
124 kfree(runtime);
125 return -ENOMEM;
126 }
127 runtime->appl_ptr = runtime->hw_ptr = 0;
128 substream->runtime = runtime;
129 return 0;
130}
131
132static int snd_rawmidi_runtime_free(snd_rawmidi_substream_t * substream)
133{
134 snd_rawmidi_runtime_t *runtime = substream->runtime;
135
136 kfree(runtime->buffer);
137 kfree(runtime);
138 substream->runtime = NULL;
139 return 0;
140}
141
142static inline void snd_rawmidi_output_trigger(snd_rawmidi_substream_t * substream, int up)
143{
144 if (up) {
145 tasklet_hi_schedule(&substream->runtime->tasklet);
146 } else {
147 tasklet_kill(&substream->runtime->tasklet);
148 substream->ops->trigger(substream, 0);
149 }
150}
151
152static void snd_rawmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
153{
154 substream->ops->trigger(substream, up);
155 if (!up && substream->runtime->event)
156 tasklet_kill(&substream->runtime->tasklet);
157}
158
159int snd_rawmidi_drop_output(snd_rawmidi_substream_t * substream)
160{
161 unsigned long flags;
162 snd_rawmidi_runtime_t *runtime = substream->runtime;
163
164 snd_rawmidi_output_trigger(substream, 0);
165 runtime->drain = 0;
166 spin_lock_irqsave(&runtime->lock, flags);
167 runtime->appl_ptr = runtime->hw_ptr = 0;
168 runtime->avail = runtime->buffer_size;
169 spin_unlock_irqrestore(&runtime->lock, flags);
170 return 0;
171}
172
173int snd_rawmidi_drain_output(snd_rawmidi_substream_t * substream)
174{
175 int err;
176 long timeout;
177 snd_rawmidi_runtime_t *runtime = substream->runtime;
178
179 err = 0;
180 runtime->drain = 1;
181 timeout = wait_event_interruptible_timeout(runtime->sleep,
182 (runtime->avail >= runtime->buffer_size),
183 10*HZ);
184 if (signal_pending(current))
185 err = -ERESTARTSYS;
186 if (runtime->avail < runtime->buffer_size && !timeout) {
187 snd_printk(KERN_WARNING "rawmidi drain error (avail = %li, buffer_size = %li)\n", (long)runtime->avail, (long)runtime->buffer_size);
188 err = -EIO;
189 }
190 runtime->drain = 0;
191 if (err != -ERESTARTSYS) {
192 /* we need wait a while to make sure that Tx FIFOs are empty */
193 if (substream->ops->drain)
194 substream->ops->drain(substream);
195 else
196 msleep(50);
197 snd_rawmidi_drop_output(substream);
198 }
199 return err;
200}
201
202int snd_rawmidi_drain_input(snd_rawmidi_substream_t * substream)
203{
204 unsigned long flags;
205 snd_rawmidi_runtime_t *runtime = substream->runtime;
206
207 snd_rawmidi_input_trigger(substream, 0);
208 runtime->drain = 0;
209 spin_lock_irqsave(&runtime->lock, flags);
210 runtime->appl_ptr = runtime->hw_ptr = 0;
211 runtime->avail = 0;
212 spin_unlock_irqrestore(&runtime->lock, flags);
213 return 0;
214}
215
216int snd_rawmidi_kernel_open(int cardnum, int device, int subdevice,
217 int mode, snd_rawmidi_file_t * rfile)
218{
219 snd_rawmidi_t *rmidi;
220 struct list_head *list1, *list2;
221 snd_rawmidi_substream_t *sinput = NULL, *soutput = NULL;
222 snd_rawmidi_runtime_t *input = NULL, *output = NULL;
223 int err;
224
225 if (rfile)
226 rfile->input = rfile->output = NULL;
227 rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device];
228 if (rmidi == NULL) {
229 err = -ENODEV;
230 goto __error1;
231 }
232 if (!try_module_get(rmidi->card->module)) {
233 err = -EFAULT;
234 goto __error1;
235 }
236 if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
237 down(&rmidi->open_mutex);
238 if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
239 if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT)) {
240 err = -ENXIO;
241 goto __error;
242 }
243 if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
244 err = -ENODEV;
245 goto __error;
246 }
247 if (rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened >=
248 rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_count) {
249 err = -EAGAIN;
250 goto __error;
251 }
252 }
253 if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
254 if (!(rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT)) {
255 err = -ENXIO;
256 goto __error;
257 }
258 if (subdevice >= 0 && (unsigned int)subdevice >= rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
259 err = -ENODEV;
260 goto __error;
261 }
262 if (rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened >=
263 rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_count) {
264 err = -EAGAIN;
265 goto __error;
266 }
267 }
268 list1 = rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams.next;
269 while (1) {
270 if (list1 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
271 sinput = NULL;
272 if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
273 err = -EAGAIN;
274 goto __error;
275 }
276 break;
277 }
278 sinput = list_entry(list1, snd_rawmidi_substream_t, list);
279 if ((mode & SNDRV_RAWMIDI_LFLG_INPUT) && sinput->opened)
280 goto __nexti;
281 if (subdevice < 0 || (subdevice >= 0 && subdevice == sinput->number))
282 break;
283 __nexti:
284 list1 = list1->next;
285 }
286 list2 = rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams.next;
287 while (1) {
288 if (list2 == &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
289 soutput = NULL;
290 if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
291 err = -EAGAIN;
292 goto __error;
293 }
294 break;
295 }
296 soutput = list_entry(list2, snd_rawmidi_substream_t, list);
297 if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
298 if (mode & SNDRV_RAWMIDI_LFLG_APPEND) {
299 if (soutput->opened && !soutput->append)
300 goto __nexto;
301 } else {
302 if (soutput->opened)
303 goto __nexto;
304 }
305 }
306 if (subdevice < 0 || (subdevice >= 0 && subdevice == soutput->number))
307 break;
308 __nexto:
309 list2 = list2->next;
310 }
311 if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
312 if ((err = snd_rawmidi_runtime_create(sinput)) < 0)
313 goto __error;
314 input = sinput->runtime;
315 if ((err = sinput->ops->open(sinput)) < 0)
316 goto __error;
317 sinput->opened = 1;
318 rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened++;
319 } else {
320 sinput = NULL;
321 }
322 if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
323 if (soutput->opened)
324 goto __skip_output;
325 if ((err = snd_rawmidi_runtime_create(soutput)) < 0) {
326 if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
327 sinput->ops->close(sinput);
328 goto __error;
329 }
330 output = soutput->runtime;
331 if ((err = soutput->ops->open(soutput)) < 0) {
332 if (mode & SNDRV_RAWMIDI_LFLG_INPUT)
333 sinput->ops->close(sinput);
334 goto __error;
335 }
336 __skip_output:
337 soutput->opened = 1;
338 if (mode & SNDRV_RAWMIDI_LFLG_APPEND)
339 soutput->append = 1;
340 if (soutput->use_count++ == 0)
341 soutput->active_sensing = 1;
342 rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened++;
343 } else {
344 soutput = NULL;
345 }
346 if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
347 up(&rmidi->open_mutex);
348 if (rfile) {
349 rfile->rmidi = rmidi;
350 rfile->input = sinput;
351 rfile->output = soutput;
352 }
353 return 0;
354
355 __error:
356 if (input != NULL)
357 snd_rawmidi_runtime_free(sinput);
358 if (output != NULL)
359 snd_rawmidi_runtime_free(soutput);
360 module_put(rmidi->card->module);
361 if (!(mode & SNDRV_RAWMIDI_LFLG_NOOPENLOCK))
362 up(&rmidi->open_mutex);
363 __error1:
364 return err;
365}
366
367static int snd_rawmidi_open(struct inode *inode, struct file *file)
368{
369 int maj = imajor(inode);
370 int cardnum;
371 snd_card_t *card;
372 int device, subdevice;
373 unsigned short fflags;
374 int err;
375 snd_rawmidi_t *rmidi;
376 snd_rawmidi_file_t *rawmidi_file;
377 wait_queue_t wait;
378 struct list_head *list;
379 snd_ctl_file_t *kctl;
380
381 switch (maj) {
382 case CONFIG_SND_MAJOR:
383 cardnum = SNDRV_MINOR_CARD(iminor(inode));
384 cardnum %= SNDRV_CARDS;
385 device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_RAWMIDI;
386 device %= SNDRV_MINOR_RAWMIDIS;
387 break;
388#ifdef CONFIG_SND_OSSEMUL
389 case SOUND_MAJOR:
390 cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
391 cardnum %= SNDRV_CARDS;
392 device = SNDRV_MINOR_OSS_DEVICE(iminor(inode)) == SNDRV_MINOR_OSS_MIDI ?
393 midi_map[cardnum] : amidi_map[cardnum];
394 break;
395#endif
396 default:
397 return -ENXIO;
398 }
399
400 rmidi = snd_rawmidi_devices[(cardnum * SNDRV_RAWMIDI_DEVICES) + device];
401 if (rmidi == NULL)
402 return -ENODEV;
403#ifdef CONFIG_SND_OSSEMUL
404 if (maj == SOUND_MAJOR && !rmidi->ossreg)
405 return -ENXIO;
406#endif
407 if ((file->f_flags & O_APPEND) && !(file->f_flags & O_NONBLOCK))
408 return -EINVAL; /* invalid combination */
409 card = rmidi->card;
410 err = snd_card_file_add(card, file);
411 if (err < 0)
412 return -ENODEV;
413 fflags = snd_rawmidi_file_flags(file);
414 if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */
415 fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
416 fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
417 rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
418 if (rawmidi_file == NULL) {
419 snd_card_file_remove(card, file);
420 return -ENOMEM;
421 }
422 init_waitqueue_entry(&wait, current);
423 add_wait_queue(&rmidi->open_wait, &wait);
424 down(&rmidi->open_mutex);
425 while (1) {
426 subdevice = -1;
427 down_read(&card->controls_rwsem);
428 list_for_each(list, &card->ctl_files) {
429 kctl = snd_ctl_file(list);
430 if (kctl->pid == current->pid) {
431 subdevice = kctl->prefer_rawmidi_subdevice;
432 break;
433 }
434 }
435 up_read(&card->controls_rwsem);
436 err = snd_rawmidi_kernel_open(cardnum, device, subdevice, fflags, rawmidi_file);
437 if (err >= 0)
438 break;
439 if (err == -EAGAIN) {
440 if (file->f_flags & O_NONBLOCK) {
441 err = -EBUSY;
442 break;
443 }
444 } else
445 break;
446 set_current_state(TASK_INTERRUPTIBLE);
447 up(&rmidi->open_mutex);
448 schedule();
449 down(&rmidi->open_mutex);
450 if (signal_pending(current)) {
451 err = -ERESTARTSYS;
452 break;
453 }
454 }
455#ifdef CONFIG_SND_OSSEMUL
456 if (rawmidi_file->input && rawmidi_file->input->runtime)
457 rawmidi_file->input->runtime->oss = (maj == SOUND_MAJOR);
458 if (rawmidi_file->output && rawmidi_file->output->runtime)
459 rawmidi_file->output->runtime->oss = (maj == SOUND_MAJOR);
460#endif
461 remove_wait_queue(&rmidi->open_wait, &wait);
462 if (err >= 0) {
463 file->private_data = rawmidi_file;
464 } else {
465 snd_card_file_remove(card, file);
466 kfree(rawmidi_file);
467 }
468 up(&rmidi->open_mutex);
469 return err;
470}
471
472int snd_rawmidi_kernel_release(snd_rawmidi_file_t * rfile)
473{
474 snd_rawmidi_t *rmidi;
475 snd_rawmidi_substream_t *substream;
476 snd_rawmidi_runtime_t *runtime;
477
478 snd_assert(rfile != NULL, return -ENXIO);
479 snd_assert(rfile->input != NULL || rfile->output != NULL, return -ENXIO);
480 rmidi = rfile->rmidi;
481 down(&rmidi->open_mutex);
482 if (rfile->input != NULL) {
483 substream = rfile->input;
484 rfile->input = NULL;
485 runtime = substream->runtime;
486 snd_rawmidi_input_trigger(substream, 0);
487 substream->ops->close(substream);
488 if (runtime->private_free != NULL)
489 runtime->private_free(substream);
490 snd_rawmidi_runtime_free(substream);
491 substream->opened = 0;
492 rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substream_opened--;
493 }
494 if (rfile->output != NULL) {
495 substream = rfile->output;
496 rfile->output = NULL;
497 if (--substream->use_count == 0) {
498 runtime = substream->runtime;
499 if (substream->active_sensing) {
500 unsigned char buf = 0xfe;
501 /* sending single active sensing message to shut the device up */
502 snd_rawmidi_kernel_write(substream, &buf, 1);
503 }
504 if (snd_rawmidi_drain_output(substream) == -ERESTARTSYS)
505 snd_rawmidi_output_trigger(substream, 0);
506 substream->ops->close(substream);
507 if (runtime->private_free != NULL)
508 runtime->private_free(substream);
509 snd_rawmidi_runtime_free(substream);
510 substream->opened = 0;
511 substream->append = 0;
512 }
513 rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substream_opened--;
514 }
515 up(&rmidi->open_mutex);
516 module_put(rmidi->card->module);
517 return 0;
518}
519
520static int snd_rawmidi_release(struct inode *inode, struct file *file)
521{
522 snd_rawmidi_file_t *rfile;
523 snd_rawmidi_t *rmidi;
524 int err;
525
526 rfile = file->private_data;
527 err = snd_rawmidi_kernel_release(rfile);
528 rmidi = rfile->rmidi;
529 wake_up(&rmidi->open_wait);
530 kfree(rfile);
531 snd_card_file_remove(rmidi->card, file);
532 return err;
533}
534
535int snd_rawmidi_info(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t *info)
536{
537 snd_rawmidi_t *rmidi;
538
539 if (substream == NULL)
540 return -ENODEV;
541 rmidi = substream->rmidi;
542 memset(info, 0, sizeof(*info));
543 info->card = rmidi->card->number;
544 info->device = rmidi->device;
545 info->subdevice = substream->number;
546 info->stream = substream->stream;
547 info->flags = rmidi->info_flags;
548 strcpy(info->id, rmidi->id);
549 strcpy(info->name, rmidi->name);
550 strcpy(info->subname, substream->name);
551 info->subdevices_count = substream->pstr->substream_count;
552 info->subdevices_avail = (substream->pstr->substream_count -
553 substream->pstr->substream_opened);
554 return 0;
555}
556
557static int snd_rawmidi_info_user(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t __user * _info)
558{
559 snd_rawmidi_info_t info;
560 int err;
561 if ((err = snd_rawmidi_info(substream, &info)) < 0)
562 return err;
563 if (copy_to_user(_info, &info, sizeof(snd_rawmidi_info_t)))
564 return -EFAULT;
565 return 0;
566}
567
568int snd_rawmidi_info_select(snd_card_t *card, snd_rawmidi_info_t *info)
569{
570 snd_rawmidi_t *rmidi;
571 snd_rawmidi_str_t *pstr;
572 snd_rawmidi_substream_t *substream;
573 struct list_head *list;
574 if (info->device >= SNDRV_RAWMIDI_DEVICES)
575 return -ENXIO;
576 rmidi = snd_rawmidi_devices[card->number * SNDRV_RAWMIDI_DEVICES + info->device];
577 if (info->stream < 0 || info->stream > 1)
578 return -EINVAL;
579 pstr = &rmidi->streams[info->stream];
580 if (pstr->substream_count == 0)
581 return -ENOENT;
582 if (info->subdevice >= pstr->substream_count)
583 return -ENXIO;
584 list_for_each(list, &pstr->substreams) {
585 substream = list_entry(list, snd_rawmidi_substream_t, list);
586 if ((unsigned int)substream->number == info->subdevice)
587 return snd_rawmidi_info(substream, info);
588 }
589 return -ENXIO;
590}
591
592static int snd_rawmidi_info_select_user(snd_card_t *card,
593 snd_rawmidi_info_t __user *_info)
594{
595 int err;
596 snd_rawmidi_info_t info;
597 if (get_user(info.device, &_info->device))
598 return -EFAULT;
599 if (get_user(info.stream, &_info->stream))
600 return -EFAULT;
601 if (get_user(info.subdevice, &_info->subdevice))
602 return -EFAULT;
603 if ((err = snd_rawmidi_info_select(card, &info)) < 0)
604 return err;
605 if (copy_to_user(_info, &info, sizeof(snd_rawmidi_info_t)))
606 return -EFAULT;
607 return 0;
608}
609
610int snd_rawmidi_output_params(snd_rawmidi_substream_t * substream,
611 snd_rawmidi_params_t * params)
612{
613 char *newbuf;
614 snd_rawmidi_runtime_t *runtime = substream->runtime;
615
616 if (substream->append && substream->use_count > 1)
617 return -EBUSY;
618 snd_rawmidi_drain_output(substream);
619 if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
620 return -EINVAL;
621 }
622 if (params->avail_min < 1 || params->avail_min > params->buffer_size) {
623 return -EINVAL;
624 }
625 if (params->buffer_size != runtime->buffer_size) {
626 if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)
627 return -ENOMEM;
628 kfree(runtime->buffer);
629 runtime->buffer = newbuf;
630 runtime->buffer_size = params->buffer_size;
631 }
632 runtime->avail_min = params->avail_min;
633 substream->active_sensing = !params->no_active_sensing;
634 return 0;
635}
636
637int snd_rawmidi_input_params(snd_rawmidi_substream_t * substream,
638 snd_rawmidi_params_t * params)
639{
640 char *newbuf;
641 snd_rawmidi_runtime_t *runtime = substream->runtime;
642
643 snd_rawmidi_drain_input(substream);
644 if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) {
645 return -EINVAL;
646 }
647 if (params->avail_min < 1 || params->avail_min > params->buffer_size) {
648 return -EINVAL;
649 }
650 if (params->buffer_size != runtime->buffer_size) {
651 if ((newbuf = (char *) kmalloc(params->buffer_size, GFP_KERNEL)) == NULL)
652 return -ENOMEM;
653 kfree(runtime->buffer);
654 runtime->buffer = newbuf;
655 runtime->buffer_size = params->buffer_size;
656 }
657 runtime->avail_min = params->avail_min;
658 return 0;
659}
660
661static int snd_rawmidi_output_status(snd_rawmidi_substream_t * substream,
662 snd_rawmidi_status_t * status)
663{
664 snd_rawmidi_runtime_t *runtime = substream->runtime;
665
666 memset(status, 0, sizeof(*status));
667 status->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
668 spin_lock_irq(&runtime->lock);
669 status->avail = runtime->avail;
670 spin_unlock_irq(&runtime->lock);
671 return 0;
672}
673
674static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream,
675 snd_rawmidi_status_t * status)
676{
677 snd_rawmidi_runtime_t *runtime = substream->runtime;
678
679 memset(status, 0, sizeof(*status));
680 status->stream = SNDRV_RAWMIDI_STREAM_INPUT;
681 spin_lock_irq(&runtime->lock);
682 status->avail = runtime->avail;
683 status->xruns = runtime->xruns;
684 runtime->xruns = 0;
685 spin_unlock_irq(&runtime->lock);
686 return 0;
687}
688
689static long snd_rawmidi_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
690{
691 snd_rawmidi_file_t *rfile;
692 void __user *argp = (void __user *)arg;
693
694 rfile = file->private_data;
695 if (((cmd >> 8) & 0xff) != 'W')
696 return -ENOTTY;
697 switch (cmd) {
698 case SNDRV_RAWMIDI_IOCTL_PVERSION:
699 return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0;
700 case SNDRV_RAWMIDI_IOCTL_INFO:
701 {
702 snd_rawmidi_stream_t stream;
703 snd_rawmidi_info_t __user *info = argp;
704 if (get_user(stream, &info->stream))
705 return -EFAULT;
706 switch (stream) {
707 case SNDRV_RAWMIDI_STREAM_INPUT:
708 return snd_rawmidi_info_user(rfile->input, info);
709 case SNDRV_RAWMIDI_STREAM_OUTPUT:
710 return snd_rawmidi_info_user(rfile->output, info);
711 default:
712 return -EINVAL;
713 }
714 }
715 case SNDRV_RAWMIDI_IOCTL_PARAMS:
716 {
717 snd_rawmidi_params_t params;
718 if (copy_from_user(&params, argp, sizeof(snd_rawmidi_params_t)))
719 return -EFAULT;
720 switch (params.stream) {
721 case SNDRV_RAWMIDI_STREAM_OUTPUT:
722 if (rfile->output == NULL)
723 return -EINVAL;
724 return snd_rawmidi_output_params(rfile->output, &params);
725 case SNDRV_RAWMIDI_STREAM_INPUT:
726 if (rfile->input == NULL)
727 return -EINVAL;
728 return snd_rawmidi_input_params(rfile->input, &params);
729 default:
730 return -EINVAL;
731 }
732 }
733 case SNDRV_RAWMIDI_IOCTL_STATUS:
734 {
735 int err = 0;
736 snd_rawmidi_status_t status;
737 if (copy_from_user(&status, argp, sizeof(snd_rawmidi_status_t)))
738 return -EFAULT;
739 switch (status.stream) {
740 case SNDRV_RAWMIDI_STREAM_OUTPUT:
741 if (rfile->output == NULL)
742 return -EINVAL;
743 err = snd_rawmidi_output_status(rfile->output, &status);
744 break;
745 case SNDRV_RAWMIDI_STREAM_INPUT:
746 if (rfile->input == NULL)
747 return -EINVAL;
748 err = snd_rawmidi_input_status(rfile->input, &status);
749 break;
750 default:
751 return -EINVAL;
752 }
753 if (err < 0)
754 return err;
755 if (copy_to_user(argp, &status, sizeof(snd_rawmidi_status_t)))
756 return -EFAULT;
757 return 0;
758 }
759 case SNDRV_RAWMIDI_IOCTL_DROP:
760 {
761 int val;
762 if (get_user(val, (int __user *) argp))
763 return -EFAULT;
764 switch (val) {
765 case SNDRV_RAWMIDI_STREAM_OUTPUT:
766 if (rfile->output == NULL)
767 return -EINVAL;
768 return snd_rawmidi_drop_output(rfile->output);
769 default:
770 return -EINVAL;
771 }
772 }
773 case SNDRV_RAWMIDI_IOCTL_DRAIN:
774 {
775 int val;
776 if (get_user(val, (int __user *) argp))
777 return -EFAULT;
778 switch (val) {
779 case SNDRV_RAWMIDI_STREAM_OUTPUT:
780 if (rfile->output == NULL)
781 return -EINVAL;
782 return snd_rawmidi_drain_output(rfile->output);
783 case SNDRV_RAWMIDI_STREAM_INPUT:
784 if (rfile->input == NULL)
785 return -EINVAL;
786 return snd_rawmidi_drain_input(rfile->input);
787 default:
788 return -EINVAL;
789 }
790 }
791#ifdef CONFIG_SND_DEBUG
792 default:
793 snd_printk(KERN_WARNING "rawmidi: unknown command = 0x%x\n", cmd);
794#endif
795 }
796 return -ENOTTY;
797}
798
799static int snd_rawmidi_control_ioctl(snd_card_t * card,
800 snd_ctl_file_t * control,
801 unsigned int cmd,
802 unsigned long arg)
803{
804 void __user *argp = (void __user *)arg;
805 unsigned int tmp;
806
807 tmp = card->number * SNDRV_RAWMIDI_DEVICES;
808 switch (cmd) {
809 case SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE:
810 {
811 int device;
812
813 if (get_user(device, (int __user *)argp))
814 return -EFAULT;
815 device = device < 0 ? 0 : device + 1;
816 while (device < SNDRV_RAWMIDI_DEVICES) {
817 if (snd_rawmidi_devices[tmp + device])
818 break;
819 device++;
820 }
821 if (device == SNDRV_RAWMIDI_DEVICES)
822 device = -1;
823 if (put_user(device, (int __user *)argp))
824 return -EFAULT;
825 return 0;
826 }
827 case SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE:
828 {
829 int val;
830
831 if (get_user(val, (int __user *)argp))
832 return -EFAULT;
833 control->prefer_rawmidi_subdevice = val;
834 return 0;
835 }
836 case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
837 return snd_rawmidi_info_select_user(card, argp);
838 }
839 return -ENOIOCTLCMD;
840}
841
842/**
843 * snd_rawmidi_receive - receive the input data from the device
844 * @substream: the rawmidi substream
845 * @buffer: the buffer pointer
846 * @count: the data size to read
847 *
848 * Reads the data from the internal buffer.
849 *
850 * Returns the size of read data, or a negative error code on failure.
851 */
852int snd_rawmidi_receive(snd_rawmidi_substream_t * substream, const unsigned char *buffer, int count)
853{
854 unsigned long flags;
855 int result = 0, count1;
856 snd_rawmidi_runtime_t *runtime = substream->runtime;
857
858 if (runtime->buffer == NULL) {
859 snd_printd("snd_rawmidi_receive: input is not active!!!\n");
860 return -EINVAL;
861 }
862 spin_lock_irqsave(&runtime->lock, flags);
863 if (count == 1) { /* special case, faster code */
864 substream->bytes++;
865 if (runtime->avail < runtime->buffer_size) {
866 runtime->buffer[runtime->hw_ptr++] = buffer[0];
867 runtime->hw_ptr %= runtime->buffer_size;
868 runtime->avail++;
869 result++;
870 } else {
871 runtime->xruns++;
872 }
873 } else {
874 substream->bytes += count;
875 count1 = runtime->buffer_size - runtime->hw_ptr;
876 if (count1 > count)
877 count1 = count;
878 if (count1 > (int)(runtime->buffer_size - runtime->avail))
879 count1 = runtime->buffer_size - runtime->avail;
880 memcpy(runtime->buffer + runtime->hw_ptr, buffer, count1);
881 runtime->hw_ptr += count1;
882 runtime->hw_ptr %= runtime->buffer_size;
883 runtime->avail += count1;
884 count -= count1;
885 result += count1;
886 if (count > 0) {
887 buffer += count1;
888 count1 = count;
889 if (count1 > (int)(runtime->buffer_size - runtime->avail)) {
890 count1 = runtime->buffer_size - runtime->avail;
891 runtime->xruns += count - count1;
892 }
893 if (count1 > 0) {
894 memcpy(runtime->buffer, buffer, count1);
895 runtime->hw_ptr = count1;
896 runtime->avail += count1;
897 result += count1;
898 }
899 }
900 }
901 if (result > 0) {
902 if (runtime->event)
903 tasklet_hi_schedule(&runtime->tasklet);
904 else if (snd_rawmidi_ready(substream))
905 wake_up(&runtime->sleep);
906 }
907 spin_unlock_irqrestore(&runtime->lock, flags);
908 return result;
909}
910
911static long snd_rawmidi_kernel_read1(snd_rawmidi_substream_t *substream,
912 unsigned char *buf, long count, int kernel)
913{
914 unsigned long flags;
915 long result = 0, count1;
916 snd_rawmidi_runtime_t *runtime = substream->runtime;
917
918 while (count > 0 && runtime->avail) {
919 count1 = runtime->buffer_size - runtime->appl_ptr;
920 if (count1 > count)
921 count1 = count;
922 spin_lock_irqsave(&runtime->lock, flags);
923 if (count1 > (int)runtime->avail)
924 count1 = runtime->avail;
925 if (kernel) {
926 memcpy(buf + result, runtime->buffer + runtime->appl_ptr, count1);
927 } else {
928 spin_unlock_irqrestore(&runtime->lock, flags);
929 if (copy_to_user((char __user *)buf + result,
930 runtime->buffer + runtime->appl_ptr, count1)) {
931 return result > 0 ? result : -EFAULT;
932 }
933 spin_lock_irqsave(&runtime->lock, flags);
934 }
935 runtime->appl_ptr += count1;
936 runtime->appl_ptr %= runtime->buffer_size;
937 runtime->avail -= count1;
938 spin_unlock_irqrestore(&runtime->lock, flags);
939 result += count1;
940 count -= count1;
941 }
942 return result;
943}
944
945long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char *buf, long count)
946{
947 snd_rawmidi_input_trigger(substream, 1);
948 return snd_rawmidi_kernel_read1(substream, buf, count, 1);
949}
950
951static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
952{
953 long result;
954 int count1;
955 snd_rawmidi_file_t *rfile;
956 snd_rawmidi_substream_t *substream;
957 snd_rawmidi_runtime_t *runtime;
958
959 rfile = file->private_data;
960 substream = rfile->input;
961 if (substream == NULL)
962 return -EIO;
963 runtime = substream->runtime;
964 snd_rawmidi_input_trigger(substream, 1);
965 result = 0;
966 while (count > 0) {
967 spin_lock_irq(&runtime->lock);
968 while (!snd_rawmidi_ready(substream)) {
969 wait_queue_t wait;
970 if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
971 spin_unlock_irq(&runtime->lock);
972 return result > 0 ? result : -EAGAIN;
973 }
974 init_waitqueue_entry(&wait, current);
975 add_wait_queue(&runtime->sleep, &wait);
976 set_current_state(TASK_INTERRUPTIBLE);
977 spin_unlock_irq(&runtime->lock);
978 schedule();
979 remove_wait_queue(&runtime->sleep, &wait);
980 if (signal_pending(current))
981 return result > 0 ? result : -ERESTARTSYS;
982 if (!runtime->avail)
983 return result > 0 ? result : -EIO;
984 spin_lock_irq(&runtime->lock);
985 }
986 spin_unlock_irq(&runtime->lock);
987 count1 = snd_rawmidi_kernel_read1(substream, (unsigned char *)buf, count, 0);
988 if (count1 < 0)
989 return result > 0 ? result : count1;
990 result += count1;
991 buf += count1;
992 count -= count1;
993 }
994 return result;
995}
996
997/**
998 * snd_rawmidi_transmit_empty - check whether the output buffer is empty
999 * @substream: the rawmidi substream
1000 *
1001 * Returns 1 if the internal output buffer is empty, 0 if not.
1002 */
1003int snd_rawmidi_transmit_empty(snd_rawmidi_substream_t * substream)
1004{
1005 snd_rawmidi_runtime_t *runtime = substream->runtime;
1006 int result;
1007 unsigned long flags;
1008
1009 if (runtime->buffer == NULL) {
1010 snd_printd("snd_rawmidi_transmit_empty: output is not active!!!\n");
1011 return 1;
1012 }
1013 spin_lock_irqsave(&runtime->lock, flags);
1014 result = runtime->avail >= runtime->buffer_size;
1015 spin_unlock_irqrestore(&runtime->lock, flags);
1016 return result;
1017}
1018
1019/**
1020 * snd_rawmidi_transmit_peek - copy data from the internal buffer
1021 * @substream: the rawmidi substream
1022 * @buffer: the buffer pointer
1023 * @count: data size to transfer
1024 *
1025 * Copies data from the internal output buffer to the given buffer.
1026 *
1027 * Call this in the interrupt handler when the midi output is ready,
1028 * and call snd_rawmidi_transmit_ack() after the transmission is
1029 * finished.
1030 *
1031 * Returns the size of copied data, or a negative error code on failure.
1032 */
1033int snd_rawmidi_transmit_peek(snd_rawmidi_substream_t * substream, unsigned char *buffer, int count)
1034{
1035 unsigned long flags;
1036 int result, count1;
1037 snd_rawmidi_runtime_t *runtime = substream->runtime;
1038
1039 if (runtime->buffer == NULL) {
1040 snd_printd("snd_rawmidi_transmit_peek: output is not active!!!\n");
1041 return -EINVAL;
1042 }
1043 result = 0;
1044 spin_lock_irqsave(&runtime->lock, flags);
1045 if (runtime->avail >= runtime->buffer_size) {
1046 /* warning: lowlevel layer MUST trigger down the hardware */
1047 goto __skip;
1048 }
1049 if (count == 1) { /* special case, faster code */
1050 *buffer = runtime->buffer[runtime->hw_ptr];
1051 result++;
1052 } else {
1053 count1 = runtime->buffer_size - runtime->hw_ptr;
1054 if (count1 > count)
1055 count1 = count;
1056 if (count1 > (int)(runtime->buffer_size - runtime->avail))
1057 count1 = runtime->buffer_size - runtime->avail;
1058 memcpy(buffer, runtime->buffer + runtime->hw_ptr, count1);
1059 count -= count1;
1060 result += count1;
1061 if (count > 0) {
1062 if (count > (int)(runtime->buffer_size - runtime->avail - count1))
1063 count = runtime->buffer_size - runtime->avail - count1;
1064 memcpy(buffer + count1, runtime->buffer, count);
1065 result += count;
1066 }
1067 }
1068 __skip:
1069 spin_unlock_irqrestore(&runtime->lock, flags);
1070 return result;
1071}
1072
1073/**
1074 * snd_rawmidi_transmit_ack - acknowledge the transmission
1075 * @substream: the rawmidi substream
1076 * @count: the tranferred count
1077 *
1078 * Advances the hardware pointer for the internal output buffer with
1079 * the given size and updates the condition.
1080 * Call after the transmission is finished.
1081 *
1082 * Returns the advanced size if successful, or a negative error code on failure.
1083 */
1084int snd_rawmidi_transmit_ack(snd_rawmidi_substream_t * substream, int count)
1085{
1086 unsigned long flags;
1087 snd_rawmidi_runtime_t *runtime = substream->runtime;
1088
1089 if (runtime->buffer == NULL) {
1090 snd_printd("snd_rawmidi_transmit_ack: output is not active!!!\n");
1091 return -EINVAL;
1092 }
1093 spin_lock_irqsave(&runtime->lock, flags);
1094 snd_assert(runtime->avail + count <= runtime->buffer_size, );
1095 runtime->hw_ptr += count;
1096 runtime->hw_ptr %= runtime->buffer_size;
1097 runtime->avail += count;
1098 substream->bytes += count;
1099 if (count > 0) {
1100 if (runtime->drain || snd_rawmidi_ready(substream))
1101 wake_up(&runtime->sleep);
1102 }
1103 spin_unlock_irqrestore(&runtime->lock, flags);
1104 return count;
1105}
1106
1107/**
1108 * snd_rawmidi_transmit - copy from the buffer to the device
1109 * @substream: the rawmidi substream
1110 * @buf: the buffer pointer
1111 * @count: the data size to transfer
1112 *
1113 * Copies data from the buffer to the device and advances the pointer.
1114 *
1115 * Returns the copied size if successful, or a negative error code on failure.
1116 */
1117int snd_rawmidi_transmit(snd_rawmidi_substream_t * substream, unsigned char *buffer, int count)
1118{
1119 count = snd_rawmidi_transmit_peek(substream, buffer, count);
1120 if (count < 0)
1121 return count;
1122 return snd_rawmidi_transmit_ack(substream, count);
1123}
1124
1125static long snd_rawmidi_kernel_write1(snd_rawmidi_substream_t * substream, const unsigned char *buf, long count, int kernel)
1126{
1127 unsigned long flags;
1128 long count1, result;
1129 snd_rawmidi_runtime_t *runtime = substream->runtime;
1130
1131 snd_assert(buf != NULL, return -EINVAL);
1132 snd_assert(runtime->buffer != NULL, return -EINVAL);
1133
1134 result = 0;
1135 spin_lock_irqsave(&runtime->lock, flags);
1136 if (substream->append) {
1137 if ((long)runtime->avail < count) {
1138 spin_unlock_irqrestore(&runtime->lock, flags);
1139 return -EAGAIN;
1140 }
1141 }
1142 while (count > 0 && runtime->avail > 0) {
1143 count1 = runtime->buffer_size - runtime->appl_ptr;
1144 if (count1 > count)
1145 count1 = count;
1146 if (count1 > (long)runtime->avail)
1147 count1 = runtime->avail;
1148 if (kernel) {
1149 memcpy(runtime->buffer + runtime->appl_ptr, buf, count1);
1150 } else {
1151 spin_unlock_irqrestore(&runtime->lock, flags);
1152 if (copy_from_user(runtime->buffer + runtime->appl_ptr,
1153 (char __user *)buf, count1)) {
1154 spin_lock_irqsave(&runtime->lock, flags);
1155 result = result > 0 ? result : -EFAULT;
1156 goto __end;
1157 }
1158 spin_lock_irqsave(&runtime->lock, flags);
1159 }
1160 runtime->appl_ptr += count1;
1161 runtime->appl_ptr %= runtime->buffer_size;
1162 runtime->avail -= count1;
1163 result += count1;
1164 buf += count1;
1165 count -= count1;
1166 }
1167 __end:
1168 count1 = runtime->avail < runtime->buffer_size;
1169 spin_unlock_irqrestore(&runtime->lock, flags);
1170 if (count1)
1171 snd_rawmidi_output_trigger(substream, 1);
1172 return result;
1173}
1174
1175long snd_rawmidi_kernel_write(snd_rawmidi_substream_t * substream, const unsigned char *buf, long count)
1176{
1177 return snd_rawmidi_kernel_write1(substream, buf, count, 1);
1178}
1179
1180static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
1181{
1182 long result, timeout;
1183 int count1;
1184 snd_rawmidi_file_t *rfile;
1185 snd_rawmidi_runtime_t *runtime;
1186 snd_rawmidi_substream_t *substream;
1187
1188 rfile = file->private_data;
1189 substream = rfile->output;
1190 runtime = substream->runtime;
1191 /* we cannot put an atomic message to our buffer */
1192 if (substream->append && count > runtime->buffer_size)
1193 return -EIO;
1194 result = 0;
1195 while (count > 0) {
1196 spin_lock_irq(&runtime->lock);
1197 while (!snd_rawmidi_ready_append(substream, count)) {
1198 wait_queue_t wait;
1199 if (file->f_flags & O_NONBLOCK) {
1200 spin_unlock_irq(&runtime->lock);
1201 return result > 0 ? result : -EAGAIN;
1202 }
1203 init_waitqueue_entry(&wait, current);
1204 add_wait_queue(&runtime->sleep, &wait);
1205 set_current_state(TASK_INTERRUPTIBLE);
1206 spin_unlock_irq(&runtime->lock);
1207 timeout = schedule_timeout(30 * HZ);
1208 remove_wait_queue(&runtime->sleep, &wait);
1209 if (signal_pending(current))
1210 return result > 0 ? result : -ERESTARTSYS;
1211 if (!runtime->avail && !timeout)
1212 return result > 0 ? result : -EIO;
1213 spin_lock_irq(&runtime->lock);
1214 }
1215 spin_unlock_irq(&runtime->lock);
1216 count1 = snd_rawmidi_kernel_write1(substream, (unsigned char *)buf, count, 0);
1217 if (count1 < 0)
1218 return result > 0 ? result : count1;
1219 result += count1;
1220 buf += count1;
1221 if ((size_t)count1 < count && (file->f_flags & O_NONBLOCK))
1222 break;
1223 count -= count1;
1224 }
1225 if (file->f_flags & O_SYNC) {
1226 spin_lock_irq(&runtime->lock);
1227 while (runtime->avail != runtime->buffer_size) {
1228 wait_queue_t wait;
1229 unsigned int last_avail = runtime->avail;
1230 init_waitqueue_entry(&wait, current);
1231 add_wait_queue(&runtime->sleep, &wait);
1232 set_current_state(TASK_INTERRUPTIBLE);
1233 spin_unlock_irq(&runtime->lock);
1234 timeout = schedule_timeout(30 * HZ);
1235 remove_wait_queue(&runtime->sleep, &wait);
1236 if (signal_pending(current))
1237 return result > 0 ? result : -ERESTARTSYS;
1238 if (runtime->avail == last_avail && !timeout)
1239 return result > 0 ? result : -EIO;
1240 spin_lock_irq(&runtime->lock);
1241 }
1242 spin_unlock_irq(&runtime->lock);
1243 }
1244 return result;
1245}
1246
1247static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait)
1248{
1249 snd_rawmidi_file_t *rfile;
1250 snd_rawmidi_runtime_t *runtime;
1251 unsigned int mask;
1252
1253 rfile = file->private_data;
1254 if (rfile->input != NULL) {
1255 runtime = rfile->input->runtime;
1256 snd_rawmidi_input_trigger(rfile->input, 1);
1257 poll_wait(file, &runtime->sleep, wait);
1258 }
1259 if (rfile->output != NULL) {
1260 runtime = rfile->output->runtime;
1261 poll_wait(file, &runtime->sleep, wait);
1262 }
1263 mask = 0;
1264 if (rfile->input != NULL) {
1265 if (snd_rawmidi_ready(rfile->input))
1266 mask |= POLLIN | POLLRDNORM;
1267 }
1268 if (rfile->output != NULL) {
1269 if (snd_rawmidi_ready(rfile->output))
1270 mask |= POLLOUT | POLLWRNORM;
1271 }
1272 return mask;
1273}
1274
1275/*
1276 */
1277#ifdef CONFIG_COMPAT
1278#include "rawmidi_compat.c"
1279#else
1280#define snd_rawmidi_ioctl_compat NULL
1281#endif
1282
1283/*
1284
1285 */
1286
1287static void snd_rawmidi_proc_info_read(snd_info_entry_t *entry,
1288 snd_info_buffer_t * buffer)
1289{
1290 snd_rawmidi_t *rmidi;
1291 snd_rawmidi_substream_t *substream;
1292 snd_rawmidi_runtime_t *runtime;
1293 struct list_head *list;
1294
1295 rmidi = entry->private_data;
1296 snd_iprintf(buffer, "%s\n\n", rmidi->name);
1297 down(&rmidi->open_mutex);
1298 if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
1299 list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT].substreams) {
1300 substream = list_entry(list, snd_rawmidi_substream_t, list);
1301 snd_iprintf(buffer,
1302 "Output %d\n"
1303 " Tx bytes : %lu\n",
1304 substream->number,
1305 (unsigned long) substream->bytes);
1306 if (substream->opened) {
1307 runtime = substream->runtime;
1308 snd_iprintf(buffer,
1309 " Mode : %s\n"
1310 " Buffer size : %lu\n"
1311 " Avail : %lu\n",
1312 runtime->oss ? "OSS compatible" : "native",
1313 (unsigned long) runtime->buffer_size,
1314 (unsigned long) runtime->avail);
1315 }
1316 }
1317 }
1318 if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_INPUT) {
1319 list_for_each(list, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT].substreams) {
1320 substream = list_entry(list, snd_rawmidi_substream_t, list);
1321 snd_iprintf(buffer,
1322 "Input %d\n"
1323 " Rx bytes : %lu\n",
1324 substream->number,
1325 (unsigned long) substream->bytes);
1326 if (substream->opened) {
1327 runtime = substream->runtime;
1328 snd_iprintf(buffer,
1329 " Buffer size : %lu\n"
1330 " Avail : %lu\n"
1331 " Overruns : %lu\n",
1332 (unsigned long) runtime->buffer_size,
1333 (unsigned long) runtime->avail,
1334 (unsigned long) runtime->xruns);
1335 }
1336 }
1337 }
1338 up(&rmidi->open_mutex);
1339}
1340
1341/*
1342 * Register functions
1343 */
1344
1345static struct file_operations snd_rawmidi_f_ops =
1346{
1347 .owner = THIS_MODULE,
1348 .read = snd_rawmidi_read,
1349 .write = snd_rawmidi_write,
1350 .open = snd_rawmidi_open,
1351 .release = snd_rawmidi_release,
1352 .poll = snd_rawmidi_poll,
1353 .unlocked_ioctl = snd_rawmidi_ioctl,
1354 .compat_ioctl = snd_rawmidi_ioctl_compat,
1355};
1356
1357static snd_minor_t snd_rawmidi_reg =
1358{
1359 .comment = "raw midi",
1360 .f_ops = &snd_rawmidi_f_ops,
1361};
1362
1363static int snd_rawmidi_alloc_substreams(snd_rawmidi_t *rmidi,
1364 snd_rawmidi_str_t *stream,
1365 int direction,
1366 int count)
1367{
1368 snd_rawmidi_substream_t *substream;
1369 int idx;
1370
1371 INIT_LIST_HEAD(&stream->substreams);
1372 for (idx = 0; idx < count; idx++) {
1373 substream = kcalloc(1, sizeof(*substream), GFP_KERNEL);
1374 if (substream == NULL)
1375 return -ENOMEM;
1376 substream->stream = direction;
1377 substream->number = idx;
1378 substream->rmidi = rmidi;
1379 substream->pstr = stream;
1380 list_add_tail(&substream->list, &stream->substreams);
1381 stream->substream_count++;
1382 }
1383 return 0;
1384}
1385
1386/**
1387 * snd_rawmidi_new - create a rawmidi instance
1388 * @card: the card instance
1389 * @id: the id string
1390 * @device: the device index
1391 * @output_count: the number of output streams
1392 * @input_count: the number of input streams
1393 * @rrawmidi: the pointer to store the new rawmidi instance
1394 *
1395 * Creates a new rawmidi instance.
1396 * Use snd_rawmidi_set_ops() to set the operators to the new instance.
1397 *
1398 * Returns zero if successful, or a negative error code on failure.
1399 */
1400int snd_rawmidi_new(snd_card_t * card, char *id, int device,
1401 int output_count, int input_count,
1402 snd_rawmidi_t ** rrawmidi)
1403{
1404 snd_rawmidi_t *rmidi;
1405 int err;
1406 static snd_device_ops_t ops = {
1407 .dev_free = snd_rawmidi_dev_free,
1408 .dev_register = snd_rawmidi_dev_register,
1409 .dev_disconnect = snd_rawmidi_dev_disconnect,
1410 .dev_unregister = snd_rawmidi_dev_unregister
1411 };
1412
1413 snd_assert(rrawmidi != NULL, return -EINVAL);
1414 *rrawmidi = NULL;
1415 snd_assert(card != NULL, return -ENXIO);
1416 rmidi = kcalloc(1, sizeof(*rmidi), GFP_KERNEL);
1417 if (rmidi == NULL)
1418 return -ENOMEM;
1419 rmidi->card = card;
1420 rmidi->device = device;
1421 init_MUTEX(&rmidi->open_mutex);
1422 init_waitqueue_head(&rmidi->open_wait);
1423 if (id != NULL)
1424 strlcpy(rmidi->id, id, sizeof(rmidi->id));
1425 if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT], SNDRV_RAWMIDI_STREAM_INPUT, input_count)) < 0) {
1426 snd_rawmidi_free(rmidi);
1427 return err;
1428 }
1429 if ((err = snd_rawmidi_alloc_substreams(rmidi, &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT], SNDRV_RAWMIDI_STREAM_OUTPUT, output_count)) < 0) {
1430 snd_rawmidi_free(rmidi);
1431 return err;
1432 }
1433 if ((err = snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)) < 0) {
1434 snd_rawmidi_free(rmidi);
1435 return err;
1436 }
1437 *rrawmidi = rmidi;
1438 return 0;
1439}
1440
1441static void snd_rawmidi_free_substreams(snd_rawmidi_str_t *stream)
1442{
1443 snd_rawmidi_substream_t *substream;
1444
1445 while (!list_empty(&stream->substreams)) {
1446 substream = list_entry(stream->substreams.next, snd_rawmidi_substream_t, list);
1447 list_del(&substream->list);
1448 kfree(substream);
1449 }
1450}
1451
1452static int snd_rawmidi_free(snd_rawmidi_t *rmidi)
1453{
1454 snd_assert(rmidi != NULL, return -ENXIO);
1455 snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]);
1456 snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
1457 if (rmidi->private_free)
1458 rmidi->private_free(rmidi);
1459 kfree(rmidi);
1460 return 0;
1461}
1462
1463static int snd_rawmidi_dev_free(snd_device_t *device)
1464{
1465 snd_rawmidi_t *rmidi = device->device_data;
1466 return snd_rawmidi_free(rmidi);
1467}
1468
1469#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1470static void snd_rawmidi_dev_seq_free(snd_seq_device_t *device)
1471{
1472 snd_rawmidi_t *rmidi = device->private_data;
1473 rmidi->seq_dev = NULL;
1474}
1475#endif
1476
1477static int snd_rawmidi_dev_register(snd_device_t *device)
1478{
1479 int idx, err;
1480 snd_info_entry_t *entry;
1481 char name[16];
1482 snd_rawmidi_t *rmidi = device->device_data;
1483
1484 if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
1485 return -ENOMEM;
1486 down(&register_mutex);
1487 idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
1488 if (snd_rawmidi_devices[idx] != NULL) {
1489 up(&register_mutex);
1490 return -EBUSY;
1491 }
1492 snd_rawmidi_devices[idx] = rmidi;
1493 sprintf(name, "midiC%iD%i", rmidi->card->number, rmidi->device);
1494 if ((err = snd_register_device(SNDRV_DEVICE_TYPE_RAWMIDI,
1495 rmidi->card, rmidi->device,
1496 &snd_rawmidi_reg, name)) < 0) {
1497 snd_printk(KERN_ERR "unable to register rawmidi device %i:%i\n", rmidi->card->number, rmidi->device);
1498 snd_rawmidi_devices[idx] = NULL;
1499 up(&register_mutex);
1500 return err;
1501 }
1502 if (rmidi->ops && rmidi->ops->dev_register &&
1503 (err = rmidi->ops->dev_register(rmidi)) < 0) {
1504 snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
1505 snd_rawmidi_devices[idx] = NULL;
1506 up(&register_mutex);
1507 return err;
1508 }
1509#ifdef CONFIG_SND_OSSEMUL
1510 rmidi->ossreg = 0;
1511 if ((int)rmidi->device == midi_map[rmidi->card->number]) {
1512 if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
1513 rmidi->card, 0, &snd_rawmidi_reg, name) < 0) {
1514 snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0);
1515 } else {
1516 rmidi->ossreg++;
1517#ifdef SNDRV_OSS_INFO_DEV_MIDI
1518 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name);
1519#endif
1520 }
1521 }
1522 if ((int)rmidi->device == amidi_map[rmidi->card->number]) {
1523 if (snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI,
1524 rmidi->card, 1, &snd_rawmidi_reg, name) < 0) {
1525 snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 1);
1526 } else {
1527 rmidi->ossreg++;
1528 }
1529 }
1530#endif /* CONFIG_SND_OSSEMUL */
1531 up(&register_mutex);
1532 sprintf(name, "midi%d", rmidi->device);
1533 entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
1534 if (entry) {
1535 entry->private_data = rmidi;
1536 entry->c.text.read_size = 1024;
1537 entry->c.text.read = snd_rawmidi_proc_info_read;
1538 if (snd_info_register(entry) < 0) {
1539 snd_info_free_entry(entry);
1540 entry = NULL;
1541 }
1542 }
1543 rmidi->proc_entry = entry;
1544#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1545 if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */
1546 if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) {
1547 rmidi->seq_dev->private_data = rmidi;
1548 rmidi->seq_dev->private_free = snd_rawmidi_dev_seq_free;
1549 sprintf(rmidi->seq_dev->name, "MIDI %d-%d", rmidi->card->number, rmidi->device);
1550 snd_device_register(rmidi->card, rmidi->seq_dev);
1551 }
1552 }
1553#endif
1554 return 0;
1555}
1556
1557static int snd_rawmidi_dev_disconnect(snd_device_t *device)
1558{
1559 snd_rawmidi_t *rmidi = device->device_data;
1560 int idx;
1561
1562 down(&register_mutex);
1563 idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
1564 snd_rawmidi_devices[idx] = NULL;
1565 up(&register_mutex);
1566 return 0;
1567}
1568
1569static int snd_rawmidi_dev_unregister(snd_device_t *device)
1570{
1571 int idx;
1572 snd_rawmidi_t *rmidi = device->device_data;
1573
1574 snd_assert(rmidi != NULL, return -ENXIO);
1575 down(&register_mutex);
1576 idx = (rmidi->card->number * SNDRV_RAWMIDI_DEVICES) + rmidi->device;
1577 snd_rawmidi_devices[idx] = NULL;
1578 if (rmidi->proc_entry) {
1579 snd_info_unregister(rmidi->proc_entry);
1580 rmidi->proc_entry = NULL;
1581 }
1582#ifdef CONFIG_SND_OSSEMUL
1583 if (rmidi->ossreg) {
1584 if ((int)rmidi->device == midi_map[rmidi->card->number]) {
1585 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0);
1586#ifdef SNDRV_OSS_INFO_DEV_MIDI
1587 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number);
1588#endif
1589 }
1590 if ((int)rmidi->device == amidi_map[rmidi->card->number])
1591 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1);
1592 rmidi->ossreg = 0;
1593 }
1594#endif /* CONFIG_SND_OSSEMUL */
1595 if (rmidi->ops && rmidi->ops->dev_unregister)
1596 rmidi->ops->dev_unregister(rmidi);
1597 snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
1598 up(&register_mutex);
1599#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
1600 if (rmidi->seq_dev) {
1601 snd_device_free(rmidi->card, rmidi->seq_dev);
1602 rmidi->seq_dev = NULL;
1603 }
1604#endif
1605 return snd_rawmidi_free(rmidi);
1606}
1607
1608/**
1609 * snd_rawmidi_set_ops - set the rawmidi operators
1610 * @rmidi: the rawmidi instance
1611 * @stream: the stream direction, SNDRV_RAWMIDI_STREAM_XXX
1612 * @ops: the operator table
1613 *
1614 * Sets the rawmidi operators for the given stream direction.
1615 */
1616void snd_rawmidi_set_ops(snd_rawmidi_t *rmidi, int stream, snd_rawmidi_ops_t *ops)
1617{
1618 struct list_head *list;
1619 snd_rawmidi_substream_t *substream;
1620
1621 list_for_each(list, &rmidi->streams[stream].substreams) {
1622 substream = list_entry(list, snd_rawmidi_substream_t, list);
1623 substream->ops = ops;
1624 }
1625}
1626
1627/*
1628 * ENTRY functions
1629 */
1630
1631static int __init alsa_rawmidi_init(void)
1632{
1633
1634 snd_ctl_register_ioctl(snd_rawmidi_control_ioctl);
1635 snd_ctl_register_ioctl_compat(snd_rawmidi_control_ioctl);
1636#ifdef CONFIG_SND_OSSEMUL
1637 { int i;
1638 /* check device map table */
1639 for (i = 0; i < SNDRV_CARDS; i++) {
1640 if (midi_map[i] < 0 || midi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
1641 snd_printk(KERN_ERR "invalid midi_map[%d] = %d\n", i, midi_map[i]);
1642 midi_map[i] = 0;
1643 }
1644 if (amidi_map[i] < 0 || amidi_map[i] >= SNDRV_RAWMIDI_DEVICES) {
1645 snd_printk(KERN_ERR "invalid amidi_map[%d] = %d\n", i, amidi_map[i]);
1646 amidi_map[i] = 1;
1647 }
1648 }
1649 }
1650#endif /* CONFIG_SND_OSSEMUL */
1651 return 0;
1652}
1653
1654static void __exit alsa_rawmidi_exit(void)
1655{
1656 snd_ctl_unregister_ioctl(snd_rawmidi_control_ioctl);
1657 snd_ctl_unregister_ioctl_compat(snd_rawmidi_control_ioctl);
1658}
1659
1660module_init(alsa_rawmidi_init)
1661module_exit(alsa_rawmidi_exit)
1662
1663EXPORT_SYMBOL(snd_rawmidi_output_params);
1664EXPORT_SYMBOL(snd_rawmidi_input_params);
1665EXPORT_SYMBOL(snd_rawmidi_drop_output);
1666EXPORT_SYMBOL(snd_rawmidi_drain_output);
1667EXPORT_SYMBOL(snd_rawmidi_drain_input);
1668EXPORT_SYMBOL(snd_rawmidi_receive);
1669EXPORT_SYMBOL(snd_rawmidi_transmit_empty);
1670EXPORT_SYMBOL(snd_rawmidi_transmit_peek);
1671EXPORT_SYMBOL(snd_rawmidi_transmit_ack);
1672EXPORT_SYMBOL(snd_rawmidi_transmit);
1673EXPORT_SYMBOL(snd_rawmidi_new);
1674EXPORT_SYMBOL(snd_rawmidi_set_ops);
1675EXPORT_SYMBOL(snd_rawmidi_info);
1676EXPORT_SYMBOL(snd_rawmidi_info_select);
1677EXPORT_SYMBOL(snd_rawmidi_kernel_open);
1678EXPORT_SYMBOL(snd_rawmidi_kernel_release);
1679EXPORT_SYMBOL(snd_rawmidi_kernel_read);
1680EXPORT_SYMBOL(snd_rawmidi_kernel_write);
diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
new file mode 100644
index 000000000000..d97631c3f3ad
--- /dev/null
+++ b/sound/core/rawmidi_compat.c
@@ -0,0 +1,120 @@
1/*
2 * 32bit -> 64bit ioctl wrapper for raw MIDI API
3 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21/* This file included from rawmidi.c */
22
23#include <linux/compat.h>
24
25struct sndrv_rawmidi_params32 {
26 s32 stream;
27 u32 buffer_size;
28 u32 avail_min;
29 unsigned int no_active_sensing; /* avoid bit-field */
30 unsigned char reserved[16];
31} __attribute__((packed));
32
33static int snd_rawmidi_ioctl_params_compat(snd_rawmidi_file_t *rfile,
34 struct sndrv_rawmidi_params32 __user *src)
35{
36 snd_rawmidi_params_t params;
37 unsigned int val;
38
39 if (rfile->output == NULL)
40 return -EINVAL;
41 if (get_user(params.stream, &src->stream) ||
42 get_user(params.buffer_size, &src->buffer_size) ||
43 get_user(params.avail_min, &src->avail_min) ||
44 get_user(val, &src->no_active_sensing))
45 return -EFAULT;
46 params.no_active_sensing = val;
47 switch (params.stream) {
48 case SNDRV_RAWMIDI_STREAM_OUTPUT:
49 return snd_rawmidi_output_params(rfile->output, &params);
50 case SNDRV_RAWMIDI_STREAM_INPUT:
51 return snd_rawmidi_input_params(rfile->input, &params);
52 }
53 return -EINVAL;
54}
55
56struct sndrv_rawmidi_status32 {
57 s32 stream;
58 struct compat_timespec tstamp;
59 u32 avail;
60 u32 xruns;
61 unsigned char reserved[16];
62} __attribute__((packed));
63
64static int snd_rawmidi_ioctl_status_compat(snd_rawmidi_file_t *rfile,
65 struct sndrv_rawmidi_status32 __user *src)
66{
67 int err;
68 snd_rawmidi_status_t status;
69
70 if (rfile->output == NULL)
71 return -EINVAL;
72 if (get_user(status.stream, &src->stream))
73 return -EFAULT;
74
75 switch (status.stream) {
76 case SNDRV_RAWMIDI_STREAM_OUTPUT:
77 err = snd_rawmidi_output_status(rfile->output, &status);
78 break;
79 case SNDRV_RAWMIDI_STREAM_INPUT:
80 err = snd_rawmidi_input_status(rfile->input, &status);
81 break;
82 default:
83 return -EINVAL;
84 }
85 if (err < 0)
86 return err;
87
88 if (put_user(status.tstamp.tv_sec, &src->tstamp.tv_sec) ||
89 put_user(status.tstamp.tv_nsec, &src->tstamp.tv_nsec) ||
90 put_user(status.avail, &src->avail) ||
91 put_user(status.xruns, &src->xruns))
92 return -EFAULT;
93
94 return 0;
95}
96
97enum {
98 SNDRV_RAWMIDI_IOCTL_PARAMS32 = _IOWR('W', 0x10, struct sndrv_rawmidi_params32),
99 SNDRV_RAWMIDI_IOCTL_STATUS32 = _IOWR('W', 0x20, struct sndrv_rawmidi_status32),
100};
101
102static long snd_rawmidi_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
103{
104 snd_rawmidi_file_t *rfile;
105 void __user *argp = compat_ptr(arg);
106
107 rfile = file->private_data;
108 switch (cmd) {
109 case SNDRV_RAWMIDI_IOCTL_PVERSION:
110 case SNDRV_RAWMIDI_IOCTL_INFO:
111 case SNDRV_RAWMIDI_IOCTL_DROP:
112 case SNDRV_RAWMIDI_IOCTL_DRAIN:
113 return snd_rawmidi_ioctl(file, cmd, (unsigned long)argp);
114 case SNDRV_RAWMIDI_IOCTL_PARAMS32:
115 return snd_rawmidi_ioctl_params_compat(rfile, argp);
116 case SNDRV_RAWMIDI_IOCTL_STATUS32:
117 return snd_rawmidi_ioctl_status_compat(rfile, argp);
118 }
119 return -ENOIOCTLCMD;
120}
diff --git a/sound/core/rtctimer.c b/sound/core/rtctimer.c
new file mode 100644
index 000000000000..bd5d584d284d
--- /dev/null
+++ b/sound/core/rtctimer.c
@@ -0,0 +1,188 @@
1/*
2 * RTC based high-frequency timer
3 *
4 * Copyright (C) 2000 Takashi Iwai
5 * based on rtctimer.c by Steve Ratcliffe
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <linux/init.h>
25#include <linux/time.h>
26#include <linux/threads.h>
27#include <linux/interrupt.h>
28#include <linux/moduleparam.h>
29#include <sound/core.h>
30#include <sound/timer.h>
31#include <sound/info.h>
32
33#if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
34
35#include <linux/mc146818rtc.h>
36
37#define RTC_FREQ 1024 /* default frequency */
38#define NANO_SEC 1000000000L /* 10^9 in sec */
39
40/*
41 * prototypes
42 */
43static int rtctimer_open(snd_timer_t *t);
44static int rtctimer_close(snd_timer_t *t);
45static int rtctimer_start(snd_timer_t *t);
46static int rtctimer_stop(snd_timer_t *t);
47
48
49/*
50 * The hardware dependent description for this timer.
51 */
52static struct _snd_timer_hardware rtc_hw = {
53 .flags = SNDRV_TIMER_HW_FIRST|SNDRV_TIMER_HW_AUTO,
54 .ticks = 100000000L, /* FIXME: XXX */
55 .open = rtctimer_open,
56 .close = rtctimer_close,
57 .start = rtctimer_start,
58 .stop = rtctimer_stop,
59};
60
61static int rtctimer_freq = RTC_FREQ; /* frequency */
62static snd_timer_t *rtctimer;
63static atomic_t rtc_inc = ATOMIC_INIT(0);
64static rtc_task_t rtc_task;
65
66
67static int
68rtctimer_open(snd_timer_t *t)
69{
70 int err;
71
72 err = rtc_register(&rtc_task);
73 if (err < 0)
74 return err;
75 t->private_data = &rtc_task;
76 return 0;
77}
78
79static int
80rtctimer_close(snd_timer_t *t)
81{
82 rtc_task_t *rtc = t->private_data;
83 if (rtc) {
84 rtc_unregister(rtc);
85 t->private_data = NULL;
86 }
87 return 0;
88}
89
90static int
91rtctimer_start(snd_timer_t *timer)
92{
93 rtc_task_t *rtc = timer->private_data;
94 snd_assert(rtc != NULL, return -EINVAL);
95 rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
96 rtc_control(rtc, RTC_PIE_ON, 0);
97 atomic_set(&rtc_inc, 0);
98 return 0;
99}
100
101static int
102rtctimer_stop(snd_timer_t *timer)
103{
104 rtc_task_t *rtc = timer->private_data;
105 snd_assert(rtc != NULL, return -EINVAL);
106 rtc_control(rtc, RTC_PIE_OFF, 0);
107 return 0;
108}
109
110/*
111 * interrupt
112 */
113static void rtctimer_interrupt(void *private_data)
114{
115 int ticks;
116
117 atomic_inc(&rtc_inc);
118 ticks = atomic_read(&rtc_inc);
119 snd_timer_interrupt((snd_timer_t*)private_data, ticks);
120 atomic_sub(ticks, &rtc_inc);
121}
122
123
124/*
125 * ENTRY functions
126 */
127static int __init rtctimer_init(void)
128{
129 int order, err;
130 snd_timer_t *timer;
131
132 if (rtctimer_freq < 2 || rtctimer_freq > 8192) {
133 snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq);
134 return -EINVAL;
135 }
136 for (order = 1; rtctimer_freq > order; order <<= 1)
137 ;
138 if (rtctimer_freq != order) {
139 snd_printk(KERN_ERR "rtctimer: invalid frequency %d\n", rtctimer_freq);
140 return -EINVAL;
141 }
142
143 /* Create a new timer and set up the fields */
144 err = snd_timer_global_new("rtc", SNDRV_TIMER_GLOBAL_RTC, &timer);
145 if (err < 0)
146 return err;
147
148 strcpy(timer->name, "RTC timer");
149 timer->hw = rtc_hw;
150 timer->hw.resolution = NANO_SEC / rtctimer_freq;
151
152 /* set up RTC callback */
153 rtc_task.func = rtctimer_interrupt;
154 rtc_task.private_data = timer;
155
156 err = snd_timer_global_register(timer);
157 if (err < 0) {
158 snd_timer_global_free(timer);
159 return err;
160 }
161 rtctimer = timer; /* remember this */
162
163 return 0;
164}
165
166static void __exit rtctimer_exit(void)
167{
168 if (rtctimer) {
169 snd_timer_global_unregister(rtctimer);
170 rtctimer = NULL;
171 }
172}
173
174
175/*
176 * exported stuff
177 */
178module_init(rtctimer_init)
179module_exit(rtctimer_exit)
180
181module_param(rtctimer_freq, int, 0444);
182MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz");
183
184MODULE_LICENSE("GPL");
185
186MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC));
187
188#endif /* CONFIG_RTC || CONFIG_RTC_MODULE */
diff --git a/sound/core/seq/Makefile b/sound/core/seq/Makefile
new file mode 100644
index 000000000000..64cb50d7b589
--- /dev/null
+++ b/sound/core/seq/Makefile
@@ -0,0 +1,44 @@
1#
2# Makefile for ALSA
3# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4#
5
6obj-$(CONFIG_SND) += instr/
7ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
8 obj-$(CONFIG_SND_SEQUENCER) += oss/
9endif
10
11snd-seq-device-objs := seq_device.o
12snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
13 seq_fifo.o seq_prioq.o seq_timer.o \
14 seq_system.o seq_ports.o seq_info.o
15snd-seq-midi-objs := seq_midi.o
16snd-seq-midi-emul-objs := seq_midi_emul.o
17snd-seq-midi-event-objs := seq_midi_event.o
18snd-seq-instr-objs := seq_instr.o
19snd-seq-dummy-objs := seq_dummy.o
20snd-seq-virmidi-objs := seq_virmidi.o
21
22#
23# this function returns:
24# "m" - CONFIG_SND_SEQUENCER is m
25# <empty string> - CONFIG_SND_SEQUENCER is undefined
26# otherwise parameter #1 value
27#
28sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
29
30obj-$(CONFIG_SND_SEQUENCER) += snd-seq.o snd-seq-device.o
31ifeq ($(CONFIG_SND_SEQUENCER_OSS),y)
32obj-$(CONFIG_SND_SEQUENCER) += snd-seq-midi-event.o
33endif
34obj-$(CONFIG_SND_SEQ_DUMMY) += snd-seq-dummy.o
35
36# Toplevel Module Dependency
37obj-$(CONFIG_SND_VIRMIDI) += snd-seq-virmidi.o snd-seq-midi-event.o
38obj-$(call sequencer,$(CONFIG_SND_RAWMIDI)) += snd-seq-midi.o snd-seq-midi-event.o
39obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
40obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
41obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-seq-instr.o
42obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-seq-midi-emul.o snd-seq-virmidi.o
43obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-seq-midi-emul.o snd-seq-virmidi.o
44obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-seq-midi-emul.o snd-seq-instr.o
diff --git a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile
new file mode 100644
index 000000000000..69138f30a293
--- /dev/null
+++ b/sound/core/seq/instr/Makefile
@@ -0,0 +1,23 @@
1#
2# Makefile for ALSA
3# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-ainstr-fm-objs := ainstr_fm.o
7snd-ainstr-simple-objs := ainstr_simple.o
8snd-ainstr-gf1-objs := ainstr_gf1.o
9snd-ainstr-iw-objs := ainstr_iw.o
10
11#
12# this function returns:
13# "m" - CONFIG_SND_SEQUENCER is m
14# <empty string> - CONFIG_SND_SEQUENCER is undefined
15# otherwise parameter #1 value
16#
17sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
18
19# Toplevel Module Dependency
20obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-ainstr-fm.o
21obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-ainstr-fm.o
22obj-$(call sequencer,$(CONFIG_SND_GUS_SYNTH)) += snd-ainstr-gf1.o snd-ainstr-simple.o snd-ainstr-iw.o
23obj-$(call sequencer,$(CONFIG_SND_TRIDENT)) += snd-ainstr-simple.o
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c
new file mode 100644
index 000000000000..5c671e69884f
--- /dev/null
+++ b/sound/core/seq/instr/ainstr_fm.c
@@ -0,0 +1,156 @@
1/*
2 * FM (OPL2/3) Instrument routines
3 * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/sched.h>
24#include <sound/core.h>
25#include <sound/ainstr_fm.h>
26#include <sound/initval.h>
27#include <asm/uaccess.h>
28
29MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
30MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support.");
31MODULE_LICENSE("GPL");
32
33static int snd_seq_fm_put(void *private_data, snd_seq_kinstr_t *instr,
34 char __user *instr_data, long len, int atomic, int cmd)
35{
36 fm_instrument_t *ip;
37 fm_xinstrument_t ix;
38 int idx;
39
40 if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
41 return -EINVAL;
42 /* copy instrument data */
43 if (len < (long)sizeof(ix))
44 return -EINVAL;
45 if (copy_from_user(&ix, instr_data, sizeof(ix)))
46 return -EFAULT;
47 if (ix.stype != FM_STRU_INSTR)
48 return -EINVAL;
49 ip = (fm_instrument_t *)KINSTR_DATA(instr);
50 ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
51 ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
52 ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
53 ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
54 ip->type = ix.type;
55 for (idx = 0; idx < 4; idx++) {
56 ip->op[idx].am_vib = ix.op[idx].am_vib;
57 ip->op[idx].ksl_level = ix.op[idx].ksl_level;
58 ip->op[idx].attack_decay = ix.op[idx].attack_decay;
59 ip->op[idx].sustain_release = ix.op[idx].sustain_release;
60 ip->op[idx].wave_select = ix.op[idx].wave_select;
61 }
62 for (idx = 0; idx < 2; idx++) {
63 ip->feedback_connection[idx] = ix.feedback_connection[idx];
64 }
65 ip->echo_delay = ix.echo_delay;
66 ip->echo_atten = ix.echo_atten;
67 ip->chorus_spread = ix.chorus_spread;
68 ip->trnsps = ix.trnsps;
69 ip->fix_dur = ix.fix_dur;
70 ip->modes = ix.modes;
71 ip->fix_key = ix.fix_key;
72 return 0;
73}
74
75static int snd_seq_fm_get(void *private_data, snd_seq_kinstr_t *instr,
76 char __user *instr_data, long len, int atomic,
77 int cmd)
78{
79 fm_instrument_t *ip;
80 fm_xinstrument_t ix;
81 int idx;
82
83 if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
84 return -EINVAL;
85 if (len < (long)sizeof(ix))
86 return -ENOMEM;
87 memset(&ix, 0, sizeof(ix));
88 ip = (fm_instrument_t *)KINSTR_DATA(instr);
89 ix.stype = FM_STRU_INSTR;
90 ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
91 ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
92 ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
93 ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
94 ix.type = ip->type;
95 for (idx = 0; idx < 4; idx++) {
96 ix.op[idx].am_vib = ip->op[idx].am_vib;
97 ix.op[idx].ksl_level = ip->op[idx].ksl_level;
98 ix.op[idx].attack_decay = ip->op[idx].attack_decay;
99 ix.op[idx].sustain_release = ip->op[idx].sustain_release;
100 ix.op[idx].wave_select = ip->op[idx].wave_select;
101 }
102 for (idx = 0; idx < 2; idx++) {
103 ix.feedback_connection[idx] = ip->feedback_connection[idx];
104 }
105 if (copy_to_user(instr_data, &ix, sizeof(ix)))
106 return -EFAULT;
107 ix.echo_delay = ip->echo_delay;
108 ix.echo_atten = ip->echo_atten;
109 ix.chorus_spread = ip->chorus_spread;
110 ix.trnsps = ip->trnsps;
111 ix.fix_dur = ip->fix_dur;
112 ix.modes = ip->modes;
113 ix.fix_key = ip->fix_key;
114 return 0;
115}
116
117static int snd_seq_fm_get_size(void *private_data, snd_seq_kinstr_t *instr,
118 long *size)
119{
120 *size = sizeof(fm_xinstrument_t);
121 return 0;
122}
123
124int snd_seq_fm_init(snd_seq_kinstr_ops_t *ops,
125 snd_seq_kinstr_ops_t *next)
126{
127 memset(ops, 0, sizeof(*ops));
128 // ops->private_data = private_data;
129 ops->add_len = sizeof(fm_instrument_t);
130 ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3;
131 ops->put = snd_seq_fm_put;
132 ops->get = snd_seq_fm_get;
133 ops->get_size = snd_seq_fm_get_size;
134 // ops->remove = snd_seq_fm_remove;
135 // ops->notify = snd_seq_fm_notify;
136 ops->next = next;
137 return 0;
138}
139
140/*
141 * Init part
142 */
143
144static int __init alsa_ainstr_fm_init(void)
145{
146 return 0;
147}
148
149static void __exit alsa_ainstr_fm_exit(void)
150{
151}
152
153module_init(alsa_ainstr_fm_init)
154module_exit(alsa_ainstr_fm_exit)
155
156EXPORT_SYMBOL(snd_seq_fm_init);
diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c
new file mode 100644
index 000000000000..0779c41ca037
--- /dev/null
+++ b/sound/core/seq/instr/ainstr_gf1.c
@@ -0,0 +1,358 @@
1/*
2 * GF1 (GUS) Patch - Instrument routines
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/sched.h>
24#include <linux/slab.h>
25#include <sound/core.h>
26#include <sound/ainstr_gf1.h>
27#include <sound/initval.h>
28#include <asm/uaccess.h>
29
30MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
31MODULE_DESCRIPTION("Advanced Linux Sound Architecture GF1 (GUS) Patch support.");
32MODULE_LICENSE("GPL");
33
34static unsigned int snd_seq_gf1_size(unsigned int size, unsigned int format)
35{
36 unsigned int result = size;
37
38 if (format & GF1_WAVE_16BIT)
39 result <<= 1;
40 if (format & GF1_WAVE_STEREO)
41 result <<= 1;
42 return format;
43}
44
45static int snd_seq_gf1_copy_wave_from_stream(snd_gf1_ops_t *ops,
46 gf1_instrument_t *ip,
47 char __user **data,
48 long *len,
49 int atomic)
50{
51 gf1_wave_t *wp, *prev;
52 gf1_xwave_t xp;
53 int err, gfp_mask;
54 unsigned int real_size;
55
56 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
57 if (*len < (long)sizeof(xp))
58 return -EINVAL;
59 if (copy_from_user(&xp, *data, sizeof(xp)))
60 return -EFAULT;
61 *data += sizeof(xp);
62 *len -= sizeof(xp);
63 wp = kcalloc(1, sizeof(*wp), gfp_mask);
64 if (wp == NULL)
65 return -ENOMEM;
66 wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
67 wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
68 wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
69 wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
70 wp->format = le32_to_cpu(xp.format);
71 wp->size = le32_to_cpu(xp.size);
72 wp->start = le32_to_cpu(xp.start);
73 wp->loop_start = le32_to_cpu(xp.loop_start);
74 wp->loop_end = le32_to_cpu(xp.loop_end);
75 wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
76 wp->flags = xp.flags;
77 wp->sample_rate = le32_to_cpu(xp.sample_rate);
78 wp->low_frequency = le32_to_cpu(xp.low_frequency);
79 wp->high_frequency = le32_to_cpu(xp.high_frequency);
80 wp->root_frequency = le32_to_cpu(xp.root_frequency);
81 wp->tune = le16_to_cpu(xp.tune);
82 wp->balance = xp.balance;
83 memcpy(wp->envelope_rate, xp.envelope_rate, 6);
84 memcpy(wp->envelope_offset, xp.envelope_offset, 6);
85 wp->tremolo_sweep = xp.tremolo_sweep;
86 wp->tremolo_rate = xp.tremolo_rate;
87 wp->tremolo_depth = xp.tremolo_depth;
88 wp->vibrato_sweep = xp.vibrato_sweep;
89 wp->vibrato_rate = xp.vibrato_rate;
90 wp->vibrato_depth = xp.vibrato_depth;
91 wp->scale_frequency = le16_to_cpu(xp.scale_frequency);
92 wp->scale_factor = le16_to_cpu(xp.scale_factor);
93 real_size = snd_seq_gf1_size(wp->size, wp->format);
94 if ((long)real_size > *len) {
95 kfree(wp);
96 return -ENOMEM;
97 }
98 if (ops->put_sample) {
99 err = ops->put_sample(ops->private_data, wp,
100 *data, real_size, atomic);
101 if (err < 0) {
102 kfree(wp);
103 return err;
104 }
105 }
106 *data += real_size;
107 *len -= real_size;
108 prev = ip->wave;
109 if (prev) {
110 while (prev->next) prev = prev->next;
111 prev->next = wp;
112 } else {
113 ip->wave = wp;
114 }
115 return 0;
116}
117
118static void snd_seq_gf1_wave_free(snd_gf1_ops_t *ops,
119 gf1_wave_t *wave,
120 int atomic)
121{
122 if (ops->remove_sample)
123 ops->remove_sample(ops->private_data, wave, atomic);
124 kfree(wave);
125}
126
127static void snd_seq_gf1_instr_free(snd_gf1_ops_t *ops,
128 gf1_instrument_t *ip,
129 int atomic)
130{
131 gf1_wave_t *wave;
132
133 while ((wave = ip->wave) != NULL) {
134 ip->wave = wave->next;
135 snd_seq_gf1_wave_free(ops, wave, atomic);
136 }
137}
138
139static int snd_seq_gf1_put(void *private_data, snd_seq_kinstr_t *instr,
140 char __user *instr_data, long len, int atomic,
141 int cmd)
142{
143 snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
144 gf1_instrument_t *ip;
145 gf1_xinstrument_t ix;
146 int err, gfp_mask;
147
148 if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
149 return -EINVAL;
150 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
151 /* copy instrument data */
152 if (len < (long)sizeof(ix))
153 return -EINVAL;
154 if (copy_from_user(&ix, instr_data, sizeof(ix)))
155 return -EFAULT;
156 if (ix.stype != GF1_STRU_INSTR)
157 return -EINVAL;
158 instr_data += sizeof(ix);
159 len -= sizeof(ix);
160 ip = (gf1_instrument_t *)KINSTR_DATA(instr);
161 ip->exclusion = le16_to_cpu(ix.exclusion);
162 ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
163 ip->effect1 = ix.effect1;
164 ip->effect1_depth = ix.effect1_depth;
165 ip->effect2 = ix.effect2;
166 ip->effect2_depth = ix.effect2_depth;
167 /* copy layers */
168 while (len > (long)sizeof(__u32)) {
169 __u32 stype;
170
171 if (copy_from_user(&stype, instr_data, sizeof(stype)))
172 return -EFAULT;
173 if (stype != GF1_STRU_WAVE) {
174 snd_seq_gf1_instr_free(ops, ip, atomic);
175 return -EINVAL;
176 }
177 err = snd_seq_gf1_copy_wave_from_stream(ops,
178 ip,
179 &instr_data,
180 &len,
181 atomic);
182 if (err < 0) {
183 snd_seq_gf1_instr_free(ops, ip, atomic);
184 return err;
185 }
186 }
187 return 0;
188}
189
190static int snd_seq_gf1_copy_wave_to_stream(snd_gf1_ops_t *ops,
191 gf1_instrument_t *ip,
192 char __user **data,
193 long *len,
194 int atomic)
195{
196 gf1_wave_t *wp;
197 gf1_xwave_t xp;
198 int err;
199 unsigned int real_size;
200
201 for (wp = ip->wave; wp; wp = wp->next) {
202 if (*len < (long)sizeof(xp))
203 return -ENOMEM;
204 memset(&xp, 0, sizeof(xp));
205 xp.stype = GF1_STRU_WAVE;
206 xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
207 xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
208 xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
209 xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
210 xp.format = cpu_to_le32(wp->format);
211 xp.size = cpu_to_le32(wp->size);
212 xp.start = cpu_to_le32(wp->start);
213 xp.loop_start = cpu_to_le32(wp->loop_start);
214 xp.loop_end = cpu_to_le32(wp->loop_end);
215 xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
216 xp.flags = wp->flags;
217 xp.sample_rate = cpu_to_le32(wp->sample_rate);
218 xp.low_frequency = cpu_to_le32(wp->low_frequency);
219 xp.high_frequency = cpu_to_le32(wp->high_frequency);
220 xp.root_frequency = cpu_to_le32(wp->root_frequency);
221 xp.tune = cpu_to_le16(wp->tune);
222 xp.balance = wp->balance;
223 memcpy(xp.envelope_rate, wp->envelope_rate, 6);
224 memcpy(xp.envelope_offset, wp->envelope_offset, 6);
225 xp.tremolo_sweep = wp->tremolo_sweep;
226 xp.tremolo_rate = wp->tremolo_rate;
227 xp.tremolo_depth = wp->tremolo_depth;
228 xp.vibrato_sweep = wp->vibrato_sweep;
229 xp.vibrato_rate = wp->vibrato_rate;
230 xp.vibrato_depth = wp->vibrato_depth;
231 xp.scale_frequency = cpu_to_le16(wp->scale_frequency);
232 xp.scale_factor = cpu_to_le16(wp->scale_factor);
233 if (copy_to_user(*data, &xp, sizeof(xp)))
234 return -EFAULT;
235 *data += sizeof(xp);
236 *len -= sizeof(xp);
237 real_size = snd_seq_gf1_size(wp->size, wp->format);
238 if (*len < (long)real_size)
239 return -ENOMEM;
240 if (ops->get_sample) {
241 err = ops->get_sample(ops->private_data, wp,
242 *data, real_size, atomic);
243 if (err < 0)
244 return err;
245 }
246 *data += wp->size;
247 *len -= wp->size;
248 }
249 return 0;
250}
251
252static int snd_seq_gf1_get(void *private_data, snd_seq_kinstr_t *instr,
253 char __user *instr_data, long len, int atomic,
254 int cmd)
255{
256 snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
257 gf1_instrument_t *ip;
258 gf1_xinstrument_t ix;
259
260 if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
261 return -EINVAL;
262 if (len < (long)sizeof(ix))
263 return -ENOMEM;
264 memset(&ix, 0, sizeof(ix));
265 ip = (gf1_instrument_t *)KINSTR_DATA(instr);
266 ix.stype = GF1_STRU_INSTR;
267 ix.exclusion = cpu_to_le16(ip->exclusion);
268 ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
269 ix.effect1 = cpu_to_le16(ip->effect1);
270 ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
271 ix.effect2 = ip->effect2;
272 ix.effect2_depth = ip->effect2_depth;
273 if (copy_to_user(instr_data, &ix, sizeof(ix)))
274 return -EFAULT;
275 instr_data += sizeof(ix);
276 len -= sizeof(ix);
277 return snd_seq_gf1_copy_wave_to_stream(ops,
278 ip,
279 &instr_data,
280 &len,
281 atomic);
282}
283
284static int snd_seq_gf1_get_size(void *private_data, snd_seq_kinstr_t *instr,
285 long *size)
286{
287 long result;
288 gf1_instrument_t *ip;
289 gf1_wave_t *wp;
290
291 *size = 0;
292 ip = (gf1_instrument_t *)KINSTR_DATA(instr);
293 result = sizeof(gf1_xinstrument_t);
294 for (wp = ip->wave; wp; wp = wp->next) {
295 result += sizeof(gf1_xwave_t);
296 result += wp->size;
297 }
298 *size = result;
299 return 0;
300}
301
302static int snd_seq_gf1_remove(void *private_data,
303 snd_seq_kinstr_t *instr,
304 int atomic)
305{
306 snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
307 gf1_instrument_t *ip;
308
309 ip = (gf1_instrument_t *)KINSTR_DATA(instr);
310 snd_seq_gf1_instr_free(ops, ip, atomic);
311 return 0;
312}
313
314static void snd_seq_gf1_notify(void *private_data,
315 snd_seq_kinstr_t *instr,
316 int what)
317{
318 snd_gf1_ops_t *ops = (snd_gf1_ops_t *)private_data;
319
320 if (ops->notify)
321 ops->notify(ops->private_data, instr, what);
322}
323
324int snd_seq_gf1_init(snd_gf1_ops_t *ops,
325 void *private_data,
326 snd_seq_kinstr_ops_t *next)
327{
328 memset(ops, 0, sizeof(*ops));
329 ops->private_data = private_data;
330 ops->kops.private_data = ops;
331 ops->kops.add_len = sizeof(gf1_instrument_t);
332 ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_GUS_PATCH;
333 ops->kops.put = snd_seq_gf1_put;
334 ops->kops.get = snd_seq_gf1_get;
335 ops->kops.get_size = snd_seq_gf1_get_size;
336 ops->kops.remove = snd_seq_gf1_remove;
337 ops->kops.notify = snd_seq_gf1_notify;
338 ops->kops.next = next;
339 return 0;
340}
341
342/*
343 * Init part
344 */
345
346static int __init alsa_ainstr_gf1_init(void)
347{
348 return 0;
349}
350
351static void __exit alsa_ainstr_gf1_exit(void)
352{
353}
354
355module_init(alsa_ainstr_gf1_init)
356module_exit(alsa_ainstr_gf1_exit)
357
358EXPORT_SYMBOL(snd_seq_gf1_init);
diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c
new file mode 100644
index 000000000000..39ff72b2aab3
--- /dev/null
+++ b/sound/core/seq/instr/ainstr_iw.c
@@ -0,0 +1,622 @@
1/*
2 * IWFFFF - AMD InterWave (tm) - Instrument routines
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/sched.h>
24#include <linux/slab.h>
25#include <sound/core.h>
26#include <sound/ainstr_iw.h>
27#include <sound/initval.h>
28#include <asm/uaccess.h>
29
30MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
31MODULE_DESCRIPTION("Advanced Linux Sound Architecture IWFFFF support.");
32MODULE_LICENSE("GPL");
33
34static unsigned int snd_seq_iwffff_size(unsigned int size, unsigned int format)
35{
36 unsigned int result = size;
37
38 if (format & IWFFFF_WAVE_16BIT)
39 result <<= 1;
40 if (format & IWFFFF_WAVE_STEREO)
41 result <<= 1;
42 return result;
43}
44
45static void snd_seq_iwffff_copy_lfo_from_stream(iwffff_lfo_t *fp,
46 iwffff_xlfo_t *fx)
47{
48 fp->freq = le16_to_cpu(fx->freq);
49 fp->depth = le16_to_cpu(fx->depth);
50 fp->sweep = le16_to_cpu(fx->sweep);
51 fp->shape = fx->shape;
52 fp->delay = fx->delay;
53}
54
55static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype,
56 iwffff_layer_t *lp,
57 iwffff_env_t *ep,
58 iwffff_xenv_t *ex,
59 char __user **data,
60 long *len,
61 int gfp_mask)
62{
63 __u32 stype;
64 iwffff_env_record_t *rp, *rp_last;
65 iwffff_xenv_record_t rx;
66 iwffff_env_point_t *pp;
67 iwffff_xenv_point_t px;
68 int points_size, idx;
69
70 ep->flags = ex->flags;
71 ep->mode = ex->mode;
72 ep->index = ex->index;
73 rp_last = NULL;
74 while (1) {
75 if (*len < (long)sizeof(__u32))
76 return -EINVAL;
77 if (copy_from_user(&stype, *data, sizeof(stype)))
78 return -EFAULT;
79 if (stype == IWFFFF_STRU_WAVE)
80 return 0;
81 if (req_stype != stype) {
82 if (stype == IWFFFF_STRU_ENV_RECP ||
83 stype == IWFFFF_STRU_ENV_RECV)
84 return 0;
85 }
86 if (*len < (long)sizeof(rx))
87 return -EINVAL;
88 if (copy_from_user(&rx, *data, sizeof(rx)))
89 return -EFAULT;
90 *data += sizeof(rx);
91 *len -= sizeof(rx);
92 points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16);
93 if (points_size > *len)
94 return -EINVAL;
95 rp = kcalloc(1, sizeof(*rp) + points_size, gfp_mask);
96 if (rp == NULL)
97 return -ENOMEM;
98 rp->nattack = le16_to_cpu(rx.nattack);
99 rp->nrelease = le16_to_cpu(rx.nrelease);
100 rp->sustain_offset = le16_to_cpu(rx.sustain_offset);
101 rp->sustain_rate = le16_to_cpu(rx.sustain_rate);
102 rp->release_rate = le16_to_cpu(rx.release_rate);
103 rp->hirange = rx.hirange;
104 pp = (iwffff_env_point_t *)(rp + 1);
105 for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
106 if (copy_from_user(&px, *data, sizeof(px)))
107 return -EFAULT;
108 *data += sizeof(px);
109 *len -= sizeof(px);
110 pp->offset = le16_to_cpu(px.offset);
111 pp->rate = le16_to_cpu(px.rate);
112 }
113 if (ep->record == NULL) {
114 ep->record = rp;
115 } else {
116 rp_last = rp;
117 }
118 rp_last = rp;
119 }
120 return 0;
121}
122
123static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops,
124 iwffff_layer_t *lp,
125 char __user **data,
126 long *len,
127 int atomic)
128{
129 iwffff_wave_t *wp, *prev;
130 iwffff_xwave_t xp;
131 int err, gfp_mask;
132 unsigned int real_size;
133
134 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
135 if (*len < (long)sizeof(xp))
136 return -EINVAL;
137 if (copy_from_user(&xp, *data, sizeof(xp)))
138 return -EFAULT;
139 *data += sizeof(xp);
140 *len -= sizeof(xp);
141 wp = kcalloc(1, sizeof(*wp), gfp_mask);
142 if (wp == NULL)
143 return -ENOMEM;
144 wp->share_id[0] = le32_to_cpu(xp.share_id[0]);
145 wp->share_id[1] = le32_to_cpu(xp.share_id[1]);
146 wp->share_id[2] = le32_to_cpu(xp.share_id[2]);
147 wp->share_id[3] = le32_to_cpu(xp.share_id[3]);
148 wp->format = le32_to_cpu(xp.format);
149 wp->address.memory = le32_to_cpu(xp.offset);
150 wp->size = le32_to_cpu(xp.size);
151 wp->start = le32_to_cpu(xp.start);
152 wp->loop_start = le32_to_cpu(xp.loop_start);
153 wp->loop_end = le32_to_cpu(xp.loop_end);
154 wp->loop_repeat = le16_to_cpu(xp.loop_repeat);
155 wp->sample_ratio = le32_to_cpu(xp.sample_ratio);
156 wp->attenuation = xp.attenuation;
157 wp->low_note = xp.low_note;
158 wp->high_note = xp.high_note;
159 real_size = snd_seq_iwffff_size(wp->size, wp->format);
160 if (!(wp->format & IWFFFF_WAVE_ROM)) {
161 if ((long)real_size > *len) {
162 kfree(wp);
163 return -ENOMEM;
164 }
165 }
166 if (ops->put_sample) {
167 err = ops->put_sample(ops->private_data, wp,
168 *data, real_size, atomic);
169 if (err < 0) {
170 kfree(wp);
171 return err;
172 }
173 }
174 if (!(wp->format & IWFFFF_WAVE_ROM)) {
175 *data += real_size;
176 *len -= real_size;
177 }
178 prev = lp->wave;
179 if (prev) {
180 while (prev->next) prev = prev->next;
181 prev->next = wp;
182 } else {
183 lp->wave = wp;
184 }
185 return 0;
186}
187
188static void snd_seq_iwffff_env_free(snd_iwffff_ops_t *ops,
189 iwffff_env_t *env,
190 int atomic)
191{
192 iwffff_env_record_t *rec;
193
194 while ((rec = env->record) != NULL) {
195 env->record = rec->next;
196 kfree(rec);
197 }
198}
199
200static void snd_seq_iwffff_wave_free(snd_iwffff_ops_t *ops,
201 iwffff_wave_t *wave,
202 int atomic)
203{
204 if (ops->remove_sample)
205 ops->remove_sample(ops->private_data, wave, atomic);
206 kfree(wave);
207}
208
209static void snd_seq_iwffff_instr_free(snd_iwffff_ops_t *ops,
210 iwffff_instrument_t *ip,
211 int atomic)
212{
213 iwffff_layer_t *layer;
214 iwffff_wave_t *wave;
215
216 while ((layer = ip->layer) != NULL) {
217 ip->layer = layer->next;
218 snd_seq_iwffff_env_free(ops, &layer->penv, atomic);
219 snd_seq_iwffff_env_free(ops, &layer->venv, atomic);
220 while ((wave = layer->wave) != NULL) {
221 layer->wave = wave->next;
222 snd_seq_iwffff_wave_free(ops, wave, atomic);
223 }
224 kfree(layer);
225 }
226}
227
228static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr,
229 char __user *instr_data, long len, int atomic,
230 int cmd)
231{
232 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
233 iwffff_instrument_t *ip;
234 iwffff_xinstrument_t ix;
235 iwffff_layer_t *lp, *prev_lp;
236 iwffff_xlayer_t lx;
237 int err, gfp_mask;
238
239 if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
240 return -EINVAL;
241 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
242 /* copy instrument data */
243 if (len < (long)sizeof(ix))
244 return -EINVAL;
245 if (copy_from_user(&ix, instr_data, sizeof(ix)))
246 return -EFAULT;
247 if (ix.stype != IWFFFF_STRU_INSTR)
248 return -EINVAL;
249 instr_data += sizeof(ix);
250 len -= sizeof(ix);
251 ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
252 ip->exclusion = le16_to_cpu(ix.exclusion);
253 ip->layer_type = le16_to_cpu(ix.layer_type);
254 ip->exclusion_group = le16_to_cpu(ix.exclusion_group);
255 ip->effect1 = ix.effect1;
256 ip->effect1_depth = ix.effect1_depth;
257 ip->effect2 = ix.effect2;
258 ip->effect2_depth = ix.effect2_depth;
259 /* copy layers */
260 prev_lp = NULL;
261 while (len > 0) {
262 if (len < (long)sizeof(iwffff_xlayer_t)) {
263 snd_seq_iwffff_instr_free(ops, ip, atomic);
264 return -EINVAL;
265 }
266 if (copy_from_user(&lx, instr_data, sizeof(lx)))
267 return -EFAULT;
268 instr_data += sizeof(lx);
269 len -= sizeof(lx);
270 if (lx.stype != IWFFFF_STRU_LAYER) {
271 snd_seq_iwffff_instr_free(ops, ip, atomic);
272 return -EINVAL;
273 }
274 lp = kcalloc(1, sizeof(*lp), gfp_mask);
275 if (lp == NULL) {
276 snd_seq_iwffff_instr_free(ops, ip, atomic);
277 return -ENOMEM;
278 }
279 if (prev_lp) {
280 prev_lp->next = lp;
281 } else {
282 ip->layer = lp;
283 }
284 prev_lp = lp;
285 lp->flags = lx.flags;
286 lp->velocity_mode = lx.velocity_mode;
287 lp->layer_event = lx.layer_event;
288 lp->low_range = lx.low_range;
289 lp->high_range = lx.high_range;
290 lp->pan = lx.pan;
291 lp->pan_freq_scale = lx.pan_freq_scale;
292 lp->attenuation = lx.attenuation;
293 snd_seq_iwffff_copy_lfo_from_stream(&lp->tremolo, &lx.tremolo);
294 snd_seq_iwffff_copy_lfo_from_stream(&lp->vibrato, &lx.vibrato);
295 lp->freq_scale = le16_to_cpu(lx.freq_scale);
296 lp->freq_center = lx.freq_center;
297 err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECP,
298 lp,
299 &lp->penv, &lx.penv,
300 &instr_data, &len,
301 gfp_mask);
302 if (err < 0) {
303 snd_seq_iwffff_instr_free(ops, ip, atomic);
304 return err;
305 }
306 err = snd_seq_iwffff_copy_env_from_stream(IWFFFF_STRU_ENV_RECV,
307 lp,
308 &lp->venv, &lx.venv,
309 &instr_data, &len,
310 gfp_mask);
311 if (err < 0) {
312 snd_seq_iwffff_instr_free(ops, ip, atomic);
313 return err;
314 }
315 while (len > (long)sizeof(__u32)) {
316 __u32 stype;
317
318 if (copy_from_user(&stype, instr_data, sizeof(stype)))
319 return -EFAULT;
320 if (stype != IWFFFF_STRU_WAVE)
321 break;
322 err = snd_seq_iwffff_copy_wave_from_stream(ops,
323 lp,
324 &instr_data,
325 &len,
326 atomic);
327 if (err < 0) {
328 snd_seq_iwffff_instr_free(ops, ip, atomic);
329 return err;
330 }
331 }
332 }
333 return 0;
334}
335
336static void snd_seq_iwffff_copy_lfo_to_stream(iwffff_xlfo_t *fx,
337 iwffff_lfo_t *fp)
338{
339 fx->freq = cpu_to_le16(fp->freq);
340 fx->depth = cpu_to_le16(fp->depth);
341 fx->sweep = cpu_to_le16(fp->sweep);
342 fp->shape = fx->shape;
343 fp->delay = fx->delay;
344}
345
346static int snd_seq_iwffff_copy_env_to_stream(__u32 req_stype,
347 iwffff_layer_t *lp,
348 iwffff_xenv_t *ex,
349 iwffff_env_t *ep,
350 char __user **data,
351 long *len)
352{
353 iwffff_env_record_t *rp;
354 iwffff_xenv_record_t rx;
355 iwffff_env_point_t *pp;
356 iwffff_xenv_point_t px;
357 int points_size, idx;
358
359 ex->flags = ep->flags;
360 ex->mode = ep->mode;
361 ex->index = ep->index;
362 for (rp = ep->record; rp; rp = rp->next) {
363 if (*len < (long)sizeof(rx))
364 return -ENOMEM;
365 memset(&rx, 0, sizeof(rx));
366 rx.stype = req_stype;
367 rx.nattack = cpu_to_le16(rp->nattack);
368 rx.nrelease = cpu_to_le16(rp->nrelease);
369 rx.sustain_offset = cpu_to_le16(rp->sustain_offset);
370 rx.sustain_rate = cpu_to_le16(rp->sustain_rate);
371 rx.release_rate = cpu_to_le16(rp->release_rate);
372 rx.hirange = cpu_to_le16(rp->hirange);
373 if (copy_to_user(*data, &rx, sizeof(rx)))
374 return -EFAULT;
375 *data += sizeof(rx);
376 *len -= sizeof(rx);
377 points_size = (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
378 if (*len < points_size)
379 return -ENOMEM;
380 pp = (iwffff_env_point_t *)(rp + 1);
381 for (idx = 0; idx < rp->nattack + rp->nrelease; idx++) {
382 px.offset = cpu_to_le16(pp->offset);
383 px.rate = cpu_to_le16(pp->rate);
384 if (copy_to_user(*data, &px, sizeof(px)))
385 return -EFAULT;
386 *data += sizeof(px);
387 *len -= sizeof(px);
388 }
389 }
390 return 0;
391}
392
393static int snd_seq_iwffff_copy_wave_to_stream(snd_iwffff_ops_t *ops,
394 iwffff_layer_t *lp,
395 char __user **data,
396 long *len,
397 int atomic)
398{
399 iwffff_wave_t *wp;
400 iwffff_xwave_t xp;
401 int err;
402 unsigned int real_size;
403
404 for (wp = lp->wave; wp; wp = wp->next) {
405 if (*len < (long)sizeof(xp))
406 return -ENOMEM;
407 memset(&xp, 0, sizeof(xp));
408 xp.stype = IWFFFF_STRU_WAVE;
409 xp.share_id[0] = cpu_to_le32(wp->share_id[0]);
410 xp.share_id[1] = cpu_to_le32(wp->share_id[1]);
411 xp.share_id[2] = cpu_to_le32(wp->share_id[2]);
412 xp.share_id[3] = cpu_to_le32(wp->share_id[3]);
413 xp.format = cpu_to_le32(wp->format);
414 if (wp->format & IWFFFF_WAVE_ROM)
415 xp.offset = cpu_to_le32(wp->address.memory);
416 xp.size = cpu_to_le32(wp->size);
417 xp.start = cpu_to_le32(wp->start);
418 xp.loop_start = cpu_to_le32(wp->loop_start);
419 xp.loop_end = cpu_to_le32(wp->loop_end);
420 xp.loop_repeat = cpu_to_le32(wp->loop_repeat);
421 xp.sample_ratio = cpu_to_le32(wp->sample_ratio);
422 xp.attenuation = wp->attenuation;
423 xp.low_note = wp->low_note;
424 xp.high_note = wp->high_note;
425 if (copy_to_user(*data, &xp, sizeof(xp)))
426 return -EFAULT;
427 *data += sizeof(xp);
428 *len -= sizeof(xp);
429 real_size = snd_seq_iwffff_size(wp->size, wp->format);
430 if (!(wp->format & IWFFFF_WAVE_ROM)) {
431 if (*len < (long)real_size)
432 return -ENOMEM;
433 }
434 if (ops->get_sample) {
435 err = ops->get_sample(ops->private_data, wp,
436 *data, real_size, atomic);
437 if (err < 0)
438 return err;
439 }
440 if (!(wp->format & IWFFFF_WAVE_ROM)) {
441 *data += real_size;
442 *len -= real_size;
443 }
444 }
445 return 0;
446}
447
448static int snd_seq_iwffff_get(void *private_data, snd_seq_kinstr_t *instr,
449 char __user *instr_data, long len, int atomic, int cmd)
450{
451 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
452 iwffff_instrument_t *ip;
453 iwffff_xinstrument_t ix;
454 iwffff_layer_t *lp;
455 iwffff_xlayer_t lx;
456 char __user *layer_instr_data;
457 int err;
458
459 if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
460 return -EINVAL;
461 if (len < (long)sizeof(ix))
462 return -ENOMEM;
463 memset(&ix, 0, sizeof(ix));
464 ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
465 ix.stype = IWFFFF_STRU_INSTR;
466 ix.exclusion = cpu_to_le16(ip->exclusion);
467 ix.layer_type = cpu_to_le16(ip->layer_type);
468 ix.exclusion_group = cpu_to_le16(ip->exclusion_group);
469 ix.effect1 = cpu_to_le16(ip->effect1);
470 ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
471 ix.effect2 = ip->effect2;
472 ix.effect2_depth = ip->effect2_depth;
473 if (copy_to_user(instr_data, &ix, sizeof(ix)))
474 return -EFAULT;
475 instr_data += sizeof(ix);
476 len -= sizeof(ix);
477 for (lp = ip->layer; lp; lp = lp->next) {
478 if (len < (long)sizeof(lx))
479 return -ENOMEM;
480 memset(&lx, 0, sizeof(lx));
481 lx.stype = IWFFFF_STRU_LAYER;
482 lx.flags = lp->flags;
483 lx.velocity_mode = lp->velocity_mode;
484 lx.layer_event = lp->layer_event;
485 lx.low_range = lp->low_range;
486 lx.high_range = lp->high_range;
487 lx.pan = lp->pan;
488 lx.pan_freq_scale = lp->pan_freq_scale;
489 lx.attenuation = lp->attenuation;
490 snd_seq_iwffff_copy_lfo_to_stream(&lx.tremolo, &lp->tremolo);
491 snd_seq_iwffff_copy_lfo_to_stream(&lx.vibrato, &lp->vibrato);
492 layer_instr_data = instr_data;
493 instr_data += sizeof(lx);
494 len -= sizeof(lx);
495 err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECP,
496 lp,
497 &lx.penv, &lp->penv,
498 &instr_data, &len);
499 if (err < 0)
500 return err;
501 err = snd_seq_iwffff_copy_env_to_stream(IWFFFF_STRU_ENV_RECV,
502 lp,
503 &lx.venv, &lp->venv,
504 &instr_data, &len);
505 if (err < 0)
506 return err;
507 /* layer structure updating is now finished */
508 if (copy_to_user(layer_instr_data, &lx, sizeof(lx)))
509 return -EFAULT;
510 err = snd_seq_iwffff_copy_wave_to_stream(ops,
511 lp,
512 &instr_data,
513 &len,
514 atomic);
515 if (err < 0)
516 return err;
517 }
518 return 0;
519}
520
521static long snd_seq_iwffff_env_size_in_stream(iwffff_env_t *ep)
522{
523 long result = 0;
524 iwffff_env_record_t *rp;
525
526 for (rp = ep->record; rp; rp = rp->next) {
527 result += sizeof(iwffff_xenv_record_t);
528 result += (rp->nattack + rp->nrelease) * 2 * sizeof(__u16);
529 }
530 return 0;
531}
532
533static long snd_seq_iwffff_wave_size_in_stream(iwffff_layer_t *lp)
534{
535 long result = 0;
536 iwffff_wave_t *wp;
537
538 for (wp = lp->wave; wp; wp = wp->next) {
539 result += sizeof(iwffff_xwave_t);
540 if (!(wp->format & IWFFFF_WAVE_ROM))
541 result += wp->size;
542 }
543 return result;
544}
545
546static int snd_seq_iwffff_get_size(void *private_data, snd_seq_kinstr_t *instr,
547 long *size)
548{
549 long result;
550 iwffff_instrument_t *ip;
551 iwffff_layer_t *lp;
552
553 *size = 0;
554 ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
555 result = sizeof(iwffff_xinstrument_t);
556 for (lp = ip->layer; lp; lp = lp->next) {
557 result += sizeof(iwffff_xlayer_t);
558 result += snd_seq_iwffff_env_size_in_stream(&lp->penv);
559 result += snd_seq_iwffff_env_size_in_stream(&lp->venv);
560 result += snd_seq_iwffff_wave_size_in_stream(lp);
561 }
562 *size = result;
563 return 0;
564}
565
566static int snd_seq_iwffff_remove(void *private_data,
567 snd_seq_kinstr_t *instr,
568 int atomic)
569{
570 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
571 iwffff_instrument_t *ip;
572
573 ip = (iwffff_instrument_t *)KINSTR_DATA(instr);
574 snd_seq_iwffff_instr_free(ops, ip, atomic);
575 return 0;
576}
577
578static void snd_seq_iwffff_notify(void *private_data,
579 snd_seq_kinstr_t *instr,
580 int what)
581{
582 snd_iwffff_ops_t *ops = (snd_iwffff_ops_t *)private_data;
583
584 if (ops->notify)
585 ops->notify(ops->private_data, instr, what);
586}
587
588int snd_seq_iwffff_init(snd_iwffff_ops_t *ops,
589 void *private_data,
590 snd_seq_kinstr_ops_t *next)
591{
592 memset(ops, 0, sizeof(*ops));
593 ops->private_data = private_data;
594 ops->kops.private_data = ops;
595 ops->kops.add_len = sizeof(iwffff_instrument_t);
596 ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_INTERWAVE;
597 ops->kops.put = snd_seq_iwffff_put;
598 ops->kops.get = snd_seq_iwffff_get;
599 ops->kops.get_size = snd_seq_iwffff_get_size;
600 ops->kops.remove = snd_seq_iwffff_remove;
601 ops->kops.notify = snd_seq_iwffff_notify;
602 ops->kops.next = next;
603 return 0;
604}
605
606/*
607 * Init part
608 */
609
610static int __init alsa_ainstr_iw_init(void)
611{
612 return 0;
613}
614
615static void __exit alsa_ainstr_iw_exit(void)
616{
617}
618
619module_init(alsa_ainstr_iw_init)
620module_exit(alsa_ainstr_iw_exit)
621
622EXPORT_SYMBOL(snd_seq_iwffff_init);
diff --git a/sound/core/seq/instr/ainstr_simple.c b/sound/core/seq/instr/ainstr_simple.c
new file mode 100644
index 000000000000..6183d2151034
--- /dev/null
+++ b/sound/core/seq/instr/ainstr_simple.c
@@ -0,0 +1,215 @@
1/*
2 * Simple (MOD player) - Instrument routines
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/sched.h>
24#include <linux/slab.h>
25#include <sound/core.h>
26#include <sound/ainstr_simple.h>
27#include <sound/initval.h>
28#include <asm/uaccess.h>
29
30MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
31MODULE_DESCRIPTION("Advanced Linux Sound Architecture Simple Instrument support.");
32MODULE_LICENSE("GPL");
33
34static unsigned int snd_seq_simple_size(unsigned int size, unsigned int format)
35{
36 unsigned int result = size;
37
38 if (format & SIMPLE_WAVE_16BIT)
39 result <<= 1;
40 if (format & SIMPLE_WAVE_STEREO)
41 result <<= 1;
42 return result;
43}
44
45static void snd_seq_simple_instr_free(snd_simple_ops_t *ops,
46 simple_instrument_t *ip,
47 int atomic)
48{
49 if (ops->remove_sample)
50 ops->remove_sample(ops->private_data, ip, atomic);
51}
52
53static int snd_seq_simple_put(void *private_data, snd_seq_kinstr_t *instr,
54 char __user *instr_data, long len,
55 int atomic, int cmd)
56{
57 snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
58 simple_instrument_t *ip;
59 simple_xinstrument_t ix;
60 int err, gfp_mask;
61 unsigned int real_size;
62
63 if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
64 return -EINVAL;
65 gfp_mask = atomic ? GFP_ATOMIC : GFP_KERNEL;
66 /* copy instrument data */
67 if (len < (long)sizeof(ix))
68 return -EINVAL;
69 if (copy_from_user(&ix, instr_data, sizeof(ix)))
70 return -EFAULT;
71 if (ix.stype != SIMPLE_STRU_INSTR)
72 return -EINVAL;
73 instr_data += sizeof(ix);
74 len -= sizeof(ix);
75 ip = (simple_instrument_t *)KINSTR_DATA(instr);
76 ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
77 ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
78 ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
79 ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
80 ip->format = le32_to_cpu(ix.format);
81 ip->size = le32_to_cpu(ix.size);
82 ip->start = le32_to_cpu(ix.start);
83 ip->loop_start = le32_to_cpu(ix.loop_start);
84 ip->loop_end = le32_to_cpu(ix.loop_end);
85 ip->loop_repeat = le16_to_cpu(ix.loop_repeat);
86 ip->effect1 = ix.effect1;
87 ip->effect1_depth = ix.effect1_depth;
88 ip->effect2 = ix.effect2;
89 ip->effect2_depth = ix.effect2_depth;
90 real_size = snd_seq_simple_size(ip->size, ip->format);
91 if (len < (long)real_size)
92 return -EINVAL;
93 if (ops->put_sample) {
94 err = ops->put_sample(ops->private_data, ip,
95 instr_data, real_size, atomic);
96 if (err < 0)
97 return err;
98 }
99 return 0;
100}
101
102static int snd_seq_simple_get(void *private_data, snd_seq_kinstr_t *instr,
103 char __user *instr_data, long len,
104 int atomic, int cmd)
105{
106 snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
107 simple_instrument_t *ip;
108 simple_xinstrument_t ix;
109 int err;
110 unsigned int real_size;
111
112 if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
113 return -EINVAL;
114 if (len < (long)sizeof(ix))
115 return -ENOMEM;
116 memset(&ix, 0, sizeof(ix));
117 ip = (simple_instrument_t *)KINSTR_DATA(instr);
118 ix.stype = SIMPLE_STRU_INSTR;
119 ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
120 ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
121 ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
122 ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
123 ix.format = cpu_to_le32(ip->format);
124 ix.size = cpu_to_le32(ip->size);
125 ix.start = cpu_to_le32(ip->start);
126 ix.loop_start = cpu_to_le32(ip->loop_start);
127 ix.loop_end = cpu_to_le32(ip->loop_end);
128 ix.loop_repeat = cpu_to_le32(ip->loop_repeat);
129 ix.effect1 = cpu_to_le16(ip->effect1);
130 ix.effect1_depth = cpu_to_le16(ip->effect1_depth);
131 ix.effect2 = ip->effect2;
132 ix.effect2_depth = ip->effect2_depth;
133 if (copy_to_user(instr_data, &ix, sizeof(ix)))
134 return -EFAULT;
135 instr_data += sizeof(ix);
136 len -= sizeof(ix);
137 real_size = snd_seq_simple_size(ip->size, ip->format);
138 if (len < (long)real_size)
139 return -ENOMEM;
140 if (ops->get_sample) {
141 err = ops->get_sample(ops->private_data, ip,
142 instr_data, real_size, atomic);
143 if (err < 0)
144 return err;
145 }
146 return 0;
147}
148
149static int snd_seq_simple_get_size(void *private_data, snd_seq_kinstr_t *instr,
150 long *size)
151{
152 simple_instrument_t *ip;
153
154 ip = (simple_instrument_t *)KINSTR_DATA(instr);
155 *size = sizeof(simple_xinstrument_t) + snd_seq_simple_size(ip->size, ip->format);
156 return 0;
157}
158
159static int snd_seq_simple_remove(void *private_data,
160 snd_seq_kinstr_t *instr,
161 int atomic)
162{
163 snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
164 simple_instrument_t *ip;
165
166 ip = (simple_instrument_t *)KINSTR_DATA(instr);
167 snd_seq_simple_instr_free(ops, ip, atomic);
168 return 0;
169}
170
171static void snd_seq_simple_notify(void *private_data,
172 snd_seq_kinstr_t *instr,
173 int what)
174{
175 snd_simple_ops_t *ops = (snd_simple_ops_t *)private_data;
176
177 if (ops->notify)
178 ops->notify(ops->private_data, instr, what);
179}
180
181int snd_seq_simple_init(snd_simple_ops_t *ops,
182 void *private_data,
183 snd_seq_kinstr_ops_t *next)
184{
185 memset(ops, 0, sizeof(*ops));
186 ops->private_data = private_data;
187 ops->kops.private_data = ops;
188 ops->kops.add_len = sizeof(simple_instrument_t);
189 ops->kops.instr_type = SNDRV_SEQ_INSTR_ID_SIMPLE;
190 ops->kops.put = snd_seq_simple_put;
191 ops->kops.get = snd_seq_simple_get;
192 ops->kops.get_size = snd_seq_simple_get_size;
193 ops->kops.remove = snd_seq_simple_remove;
194 ops->kops.notify = snd_seq_simple_notify;
195 ops->kops.next = next;
196 return 0;
197}
198
199/*
200 * Init part
201 */
202
203static int __init alsa_ainstr_simple_init(void)
204{
205 return 0;
206}
207
208static void __exit alsa_ainstr_simple_exit(void)
209{
210}
211
212module_init(alsa_ainstr_simple_init)
213module_exit(alsa_ainstr_simple_exit)
214
215EXPORT_SYMBOL(snd_seq_simple_init);
diff --git a/sound/core/seq/oss/Makefile b/sound/core/seq/oss/Makefile
new file mode 100644
index 000000000000..a37ddedf7107
--- /dev/null
+++ b/sound/core/seq/oss/Makefile
@@ -0,0 +1,10 @@
1#
2# Makefile for ALSA
3# Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4#
5
6snd-seq-oss-objs := seq_oss.o seq_oss_init.o seq_oss_timer.o seq_oss_ioctl.o \
7 seq_oss_event.o seq_oss_rw.o seq_oss_synth.o \
8 seq_oss_midi.o seq_oss_readq.o seq_oss_writeq.o
9
10obj-$(CONFIG_SND_SEQUENCER) += snd-seq-oss.o
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
new file mode 100644
index 000000000000..4c0558c0a8b4
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss.c
@@ -0,0 +1,317 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * registration of device and proc
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <sound/driver.h>
24#include <linux/init.h>
25#include <linux/smp_lock.h>
26#include <linux/moduleparam.h>
27#include <sound/core.h>
28#include <sound/minors.h>
29#include <sound/initval.h>
30#include "seq_oss_device.h"
31#include "seq_oss_synth.h"
32
33/*
34 * module option
35 */
36MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
37MODULE_DESCRIPTION("OSS-compatible sequencer module");
38MODULE_LICENSE("GPL");
39/* Takashi says this is really only for sound-service-0-, but this is OK. */
40MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER);
41MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
42
43#ifdef SNDRV_SEQ_OSS_DEBUG
44module_param(seq_oss_debug, int, 0644);
45MODULE_PARM_DESC(seq_oss_debug, "debug option");
46int seq_oss_debug = 0;
47#endif
48
49
50/*
51 * prototypes
52 */
53static int register_device(void);
54static void unregister_device(void);
55static int register_proc(void);
56static void unregister_proc(void);
57
58static int odev_open(struct inode *inode, struct file *file);
59static int odev_release(struct inode *inode, struct file *file);
60static ssize_t odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset);
61static ssize_t odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset);
62static long odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
63static unsigned int odev_poll(struct file *file, poll_table * wait);
64#ifdef CONFIG_PROC_FS
65static void info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf);
66#endif
67
68
69/*
70 * module interface
71 */
72
73static int __init alsa_seq_oss_init(void)
74{
75 int rc;
76 static snd_seq_dev_ops_t ops = {
77 snd_seq_oss_synth_register,
78 snd_seq_oss_synth_unregister,
79 };
80
81 snd_seq_autoload_lock();
82 if ((rc = register_device()) < 0)
83 goto error;
84 if ((rc = register_proc()) < 0) {
85 unregister_device();
86 goto error;
87 }
88 if ((rc = snd_seq_oss_create_client()) < 0) {
89 unregister_proc();
90 unregister_device();
91 goto error;
92 }
93
94 if ((rc = snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OSS, &ops,
95 sizeof(snd_seq_oss_reg_t))) < 0) {
96 snd_seq_oss_delete_client();
97 unregister_proc();
98 unregister_device();
99 goto error;
100 }
101
102 /* success */
103 snd_seq_oss_synth_init();
104
105 error:
106 snd_seq_autoload_unlock();
107 return rc;
108}
109
110static void __exit alsa_seq_oss_exit(void)
111{
112 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OSS);
113 snd_seq_oss_delete_client();
114 unregister_proc();
115 unregister_device();
116}
117
118module_init(alsa_seq_oss_init)
119module_exit(alsa_seq_oss_exit)
120
121/*
122 * ALSA minor device interface
123 */
124
125static DECLARE_MUTEX(register_mutex);
126
127static int
128odev_open(struct inode *inode, struct file *file)
129{
130 int level, rc;
131
132 if (iminor(inode) == SNDRV_MINOR_OSS_MUSIC)
133 level = SNDRV_SEQ_OSS_MODE_MUSIC;
134 else
135 level = SNDRV_SEQ_OSS_MODE_SYNTH;
136
137 down(&register_mutex);
138 rc = snd_seq_oss_open(file, level);
139 up(&register_mutex);
140
141 return rc;
142}
143
144static int
145odev_release(struct inode *inode, struct file *file)
146{
147 seq_oss_devinfo_t *dp;
148
149 if ((dp = file->private_data) == NULL)
150 return 0;
151
152 snd_seq_oss_drain_write(dp);
153
154 down(&register_mutex);
155 snd_seq_oss_release(dp);
156 up(&register_mutex);
157
158 return 0;
159}
160
161static ssize_t
162odev_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
163{
164 seq_oss_devinfo_t *dp;
165 dp = file->private_data;
166 snd_assert(dp != NULL, return -EIO);
167 return snd_seq_oss_read(dp, buf, count);
168}
169
170
171static ssize_t
172odev_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
173{
174 seq_oss_devinfo_t *dp;
175 dp = file->private_data;
176 snd_assert(dp != NULL, return -EIO);
177 return snd_seq_oss_write(dp, buf, count, file);
178}
179
180static long
181odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
182{
183 seq_oss_devinfo_t *dp;
184 dp = file->private_data;
185 snd_assert(dp != NULL, return -EIO);
186 return snd_seq_oss_ioctl(dp, cmd, arg);
187}
188
189#ifdef CONFIG_COMPAT
190#define odev_ioctl_compat odev_ioctl
191#else
192#define odev_ioctl_compat NULL
193#endif
194
195static unsigned int
196odev_poll(struct file *file, poll_table * wait)
197{
198 seq_oss_devinfo_t *dp;
199 dp = file->private_data;
200 snd_assert(dp != NULL, return 0);
201 return snd_seq_oss_poll(dp, file, wait);
202}
203
204/*
205 * registration of sequencer minor device
206 */
207
208static struct file_operations seq_oss_f_ops =
209{
210 .owner = THIS_MODULE,
211 .read = odev_read,
212 .write = odev_write,
213 .open = odev_open,
214 .release = odev_release,
215 .poll = odev_poll,
216 .unlocked_ioctl = odev_ioctl,
217 .compat_ioctl = odev_ioctl_compat,
218};
219
220static snd_minor_t seq_oss_reg = {
221 .comment = "sequencer",
222 .f_ops = &seq_oss_f_ops,
223};
224
225static int __init
226register_device(void)
227{
228 int rc;
229
230 down(&register_mutex);
231 if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
232 NULL, 0,
233 &seq_oss_reg,
234 SNDRV_SEQ_OSS_DEVNAME)) < 0) {
235 snd_printk(KERN_ERR "can't register device seq\n");
236 up(&register_mutex);
237 return rc;
238 }
239 if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
240 NULL, 0,
241 &seq_oss_reg,
242 SNDRV_SEQ_OSS_DEVNAME)) < 0) {
243 snd_printk(KERN_ERR "can't register device music\n");
244 snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
245 up(&register_mutex);
246 return rc;
247 }
248 debug_printk(("device registered\n"));
249 up(&register_mutex);
250 return 0;
251}
252
253static void
254unregister_device(void)
255{
256 down(&register_mutex);
257 debug_printk(("device unregistered\n"));
258 if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC, NULL, 0) < 0)
259 snd_printk(KERN_ERR "error unregister device music\n");
260 if (snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0) < 0)
261 snd_printk(KERN_ERR "error unregister device seq\n");
262 up(&register_mutex);
263}
264
265/*
266 * /proc interface
267 */
268
269#ifdef CONFIG_PROC_FS
270
271static snd_info_entry_t *info_entry;
272
273static void
274info_read(snd_info_entry_t *entry, snd_info_buffer_t *buf)
275{
276 down(&register_mutex);
277 snd_iprintf(buf, "OSS sequencer emulation version %s\n", SNDRV_SEQ_OSS_VERSION_STR);
278 snd_seq_oss_system_info_read(buf);
279 snd_seq_oss_synth_info_read(buf);
280 snd_seq_oss_midi_info_read(buf);
281 up(&register_mutex);
282}
283
284#endif /* CONFIG_PROC_FS */
285
286static int __init
287register_proc(void)
288{
289#ifdef CONFIG_PROC_FS
290 snd_info_entry_t *entry;
291
292 entry = snd_info_create_module_entry(THIS_MODULE, SNDRV_SEQ_OSS_PROCNAME, snd_seq_root);
293 if (entry == NULL)
294 return -ENOMEM;
295
296 entry->content = SNDRV_INFO_CONTENT_TEXT;
297 entry->private_data = NULL;
298 entry->c.text.read_size = 1024;
299 entry->c.text.read = info_read;
300 if (snd_info_register(entry) < 0) {
301 snd_info_free_entry(entry);
302 return -ENOMEM;
303 }
304 info_entry = entry;
305#endif
306 return 0;
307}
308
309static void
310unregister_proc(void)
311{
312#ifdef CONFIG_PROC_FS
313 if (info_entry)
314 snd_info_unregister(info_entry);
315 info_entry = NULL;
316#endif
317}
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
new file mode 100644
index 000000000000..da23c4db8dd5
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_device.h
@@ -0,0 +1,198 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
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#ifndef __SEQ_OSS_DEVICE_H
22#define __SEQ_OSS_DEVICE_H
23
24#include <sound/driver.h>
25#include <linux/time.h>
26#include <linux/wait.h>
27#include <linux/slab.h>
28#include <linux/sched.h>
29#include <sound/core.h>
30#include <sound/seq_oss.h>
31#include <sound/rawmidi.h>
32#include <sound/seq_kernel.h>
33#include <sound/info.h>
34
35/* enable debug print */
36#define SNDRV_SEQ_OSS_DEBUG
37
38/* max. applications */
39#define SNDRV_SEQ_OSS_MAX_CLIENTS 16
40#define SNDRV_SEQ_OSS_MAX_SYNTH_DEVS 16
41#define SNDRV_SEQ_OSS_MAX_MIDI_DEVS 32
42
43/* version */
44#define SNDRV_SEQ_OSS_MAJOR_VERSION 0
45#define SNDRV_SEQ_OSS_MINOR_VERSION 1
46#define SNDRV_SEQ_OSS_TINY_VERSION 8
47#define SNDRV_SEQ_OSS_VERSION_STR "0.1.8"
48
49/* device and proc interface name */
50#define SNDRV_SEQ_OSS_DEVNAME "seq_oss"
51#define SNDRV_SEQ_OSS_PROCNAME "oss"
52
53
54/*
55 * type definitions
56 */
57
58typedef struct seq_oss_devinfo_t seq_oss_devinfo_t;
59typedef struct seq_oss_writeq_t seq_oss_writeq_t;
60typedef struct seq_oss_readq_t seq_oss_readq_t;
61typedef struct seq_oss_timer_t seq_oss_timer_t;
62typedef struct seq_oss_synthinfo_t seq_oss_synthinfo_t;
63typedef struct seq_oss_synth_sysex_t seq_oss_synth_sysex_t;
64typedef struct seq_oss_chinfo_t seq_oss_chinfo_t;
65typedef unsigned int reltime_t;
66typedef unsigned int abstime_t;
67typedef union evrec_t evrec_t;
68
69
70/*
71 * synthesizer channel information
72 */
73struct seq_oss_chinfo_t {
74 int note, vel;
75};
76
77/*
78 * synthesizer information
79 */
80struct seq_oss_synthinfo_t {
81 snd_seq_oss_arg_t arg;
82 seq_oss_chinfo_t *ch;
83 seq_oss_synth_sysex_t *sysex;
84 int nr_voices;
85 int opened;
86 int is_midi;
87 int midi_mapped;
88};
89
90
91/*
92 * sequencer client information
93 */
94
95struct seq_oss_devinfo_t {
96
97 int index; /* application index */
98 int cseq; /* sequencer client number */
99 int port; /* sequencer port number */
100 int queue; /* sequencer queue number */
101
102 snd_seq_addr_t addr; /* address of this device */
103
104 int seq_mode; /* sequencer mode */
105 int file_mode; /* file access */
106
107 /* midi device table */
108 int max_mididev;
109
110 /* synth device table */
111 int max_synthdev;
112 seq_oss_synthinfo_t synths[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
113 int synth_opened;
114
115 /* output queue */
116 seq_oss_writeq_t *writeq;
117
118 /* midi input queue */
119 seq_oss_readq_t *readq;
120
121 /* timer */
122 seq_oss_timer_t *timer;
123};
124
125
126/*
127 * function prototypes
128 */
129
130/* create/delete OSS sequencer client */
131int snd_seq_oss_create_client(void);
132int snd_seq_oss_delete_client(void);
133
134/* device file interface */
135int snd_seq_oss_open(struct file *file, int level);
136void snd_seq_oss_release(seq_oss_devinfo_t *dp);
137int snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long arg);
138int snd_seq_oss_read(seq_oss_devinfo_t *dev, char __user *buf, int count);
139int snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt);
140unsigned int snd_seq_oss_poll(seq_oss_devinfo_t *dp, struct file *file, poll_table * wait);
141
142void snd_seq_oss_reset(seq_oss_devinfo_t *dp);
143void snd_seq_oss_drain_write(seq_oss_devinfo_t *dp);
144
145/* */
146void snd_seq_oss_process_queue(seq_oss_devinfo_t *dp, abstime_t time);
147
148
149/* proc interface */
150void snd_seq_oss_system_info_read(snd_info_buffer_t *buf);
151void snd_seq_oss_midi_info_read(snd_info_buffer_t *buf);
152void snd_seq_oss_synth_info_read(snd_info_buffer_t *buf);
153void snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf);
154
155/* file mode macros */
156#define is_read_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_READ)
157#define is_write_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_WRITE)
158#define is_nonblock_mode(mode) ((mode) & SNDRV_SEQ_OSS_FILE_NONBLOCK)
159
160/* dispatch event */
161inline static int
162snd_seq_oss_dispatch(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int atomic, int hop)
163{
164 return snd_seq_kernel_client_dispatch(dp->cseq, ev, atomic, hop);
165}
166
167/* ioctl */
168inline static int
169snd_seq_oss_control(seq_oss_devinfo_t *dp, unsigned int type, void *arg)
170{
171 return snd_seq_kernel_client_ctl(dp->cseq, type, arg);
172}
173
174/* fill the addresses in header */
175inline static void
176snd_seq_oss_fill_addr(seq_oss_devinfo_t *dp, snd_seq_event_t *ev,
177 int dest_client, int dest_port)
178{
179 ev->queue = dp->queue;
180 ev->source = dp->addr;
181 ev->dest.client = dest_client;
182 ev->dest.port = dest_port;
183}
184
185
186/* misc. functions for proc interface */
187char *enabled_str(int bool);
188
189
190/* for debug */
191#ifdef SNDRV_SEQ_OSS_DEBUG
192extern int seq_oss_debug;
193#define debug_printk(x) do { if (seq_oss_debug > 0) snd_printk x; } while (0)
194#else
195#define debug_printk(x) /**/
196#endif
197
198#endif /* __SEQ_OSS_DEVICE_H */
diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c
new file mode 100644
index 000000000000..58e52ddd2927
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_event.c
@@ -0,0 +1,447 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
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#include "seq_oss_device.h"
22#include "seq_oss_synth.h"
23#include "seq_oss_midi.h"
24#include "seq_oss_event.h"
25#include "seq_oss_timer.h"
26#include <sound/seq_oss_legacy.h>
27#include "seq_oss_readq.h"
28#include "seq_oss_writeq.h"
29
30
31/*
32 * prototypes
33 */
34static int extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
35static int chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
36static int chn_common_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
37static int timing_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
38static int local_event(seq_oss_devinfo_t *dp, evrec_t *event_rec, snd_seq_event_t *ev);
39static int old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
40static int note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev);
41static int note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev);
42static int set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev);
43static int set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev);
44static int set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev);
45
46
47/*
48 * convert an OSS event to ALSA event
49 * return 0 : enqueued
50 * non-zero : invalid - ignored
51 */
52
53int
54snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
55{
56 switch (q->s.code) {
57 case SEQ_EXTENDED:
58 return extended_event(dp, q, ev);
59
60 case EV_CHN_VOICE:
61 return chn_voice_event(dp, q, ev);
62
63 case EV_CHN_COMMON:
64 return chn_common_event(dp, q, ev);
65
66 case EV_TIMING:
67 return timing_event(dp, q, ev);
68
69 case EV_SEQ_LOCAL:
70 return local_event(dp, q, ev);
71
72 case EV_SYSEX:
73 return snd_seq_oss_synth_sysex(dp, q->x.dev, q->x.buf, ev);
74
75 case SEQ_MIDIPUTC:
76 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
77 return -EINVAL;
78 /* put a midi byte */
79 if (! is_write_mode(dp->file_mode))
80 break;
81 if (snd_seq_oss_midi_open(dp, q->s.dev, SNDRV_SEQ_OSS_FILE_WRITE))
82 break;
83 if (snd_seq_oss_midi_filemode(dp, q->s.dev) & SNDRV_SEQ_OSS_FILE_WRITE)
84 return snd_seq_oss_midi_putc(dp, q->s.dev, q->s.parm1, ev);
85 break;
86
87 case SEQ_ECHO:
88 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
89 return -EINVAL;
90 return set_echo_event(dp, q, ev);
91
92 case SEQ_PRIVATE:
93 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
94 return -EINVAL;
95 return snd_seq_oss_synth_raw_event(dp, q->c[1], q->c, ev);
96
97 default:
98 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
99 return -EINVAL;
100 return old_event(dp, q, ev);
101 }
102 return -EINVAL;
103}
104
105/* old type events: mode1 only */
106static int
107old_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
108{
109 switch (q->s.code) {
110 case SEQ_NOTEOFF:
111 return note_off_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
112
113 case SEQ_NOTEON:
114 return note_on_event(dp, 0, q->n.chn, q->n.note, q->n.vel, ev);
115
116 case SEQ_WAIT:
117 /* skip */
118 break;
119
120 case SEQ_PGMCHANGE:
121 return set_control_event(dp, 0, SNDRV_SEQ_EVENT_PGMCHANGE,
122 q->n.chn, 0, q->n.note, ev);
123
124 case SEQ_SYNCTIMER:
125 return snd_seq_oss_timer_reset(dp->timer);
126 }
127
128 return -EINVAL;
129}
130
131/* 8bytes extended event: mode1 only */
132static int
133extended_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
134{
135 int val;
136
137 switch (q->e.cmd) {
138 case SEQ_NOTEOFF:
139 return note_off_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
140
141 case SEQ_NOTEON:
142 return note_on_event(dp, q->e.dev, q->e.chn, q->e.p1, q->e.p2, ev);
143
144 case SEQ_PGMCHANGE:
145 return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
146 q->e.chn, 0, q->e.p1, ev);
147
148 case SEQ_AFTERTOUCH:
149 return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CHANPRESS,
150 q->e.chn, 0, q->e.p1, ev);
151
152 case SEQ_BALANCE:
153 /* convert -128:127 to 0:127 */
154 val = (char)q->e.p1;
155 val = (val + 128) / 2;
156 return set_control_event(dp, q->e.dev, SNDRV_SEQ_EVENT_CONTROLLER,
157 q->e.chn, CTL_PAN, val, ev);
158
159 case SEQ_CONTROLLER:
160 val = ((short)q->e.p3 << 8) | (short)q->e.p2;
161 switch (q->e.p1) {
162 case CTRL_PITCH_BENDER: /* SEQ1 V2 control */
163 /* -0x2000:0x1fff */
164 return set_control_event(dp, q->e.dev,
165 SNDRV_SEQ_EVENT_PITCHBEND,
166 q->e.chn, 0, val, ev);
167 case CTRL_PITCH_BENDER_RANGE:
168 /* conversion: 100/semitone -> 128/semitone */
169 return set_control_event(dp, q->e.dev,
170 SNDRV_SEQ_EVENT_REGPARAM,
171 q->e.chn, 0, val*128/100, ev);
172 default:
173 return set_control_event(dp, q->e.dev,
174 SNDRV_SEQ_EVENT_CONTROL14,
175 q->e.chn, q->e.p1, val, ev);
176 }
177
178 case SEQ_VOLMODE:
179 return snd_seq_oss_synth_raw_event(dp, q->e.dev, q->c, ev);
180
181 }
182 return -EINVAL;
183}
184
185/* channel voice events: mode1 and 2 */
186static int
187chn_voice_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
188{
189 if (q->v.chn >= 32)
190 return -EINVAL;
191 switch (q->v.cmd) {
192 case MIDI_NOTEON:
193 return note_on_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
194
195 case MIDI_NOTEOFF:
196 return note_off_event(dp, q->v.dev, q->v.chn, q->v.note, q->v.parm, ev);
197
198 case MIDI_KEY_PRESSURE:
199 return set_note_event(dp, q->v.dev, SNDRV_SEQ_EVENT_KEYPRESS,
200 q->v.chn, q->v.note, q->v.parm, ev);
201
202 }
203 return -EINVAL;
204}
205
206/* channel common events: mode1 and 2 */
207static int
208chn_common_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
209{
210 if (q->l.chn >= 32)
211 return -EINVAL;
212 switch (q->l.cmd) {
213 case MIDI_PGM_CHANGE:
214 return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PGMCHANGE,
215 q->l.chn, 0, q->l.p1, ev);
216
217 case MIDI_CTL_CHANGE:
218 return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CONTROLLER,
219 q->l.chn, q->l.p1, q->l.val, ev);
220
221 case MIDI_PITCH_BEND:
222 /* conversion: 0:0x3fff -> -0x2000:0x1fff */
223 return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_PITCHBEND,
224 q->l.chn, 0, q->l.val - 8192, ev);
225
226 case MIDI_CHN_PRESSURE:
227 return set_control_event(dp, q->l.dev, SNDRV_SEQ_EVENT_CHANPRESS,
228 q->l.chn, 0, q->l.val, ev);
229 }
230 return -EINVAL;
231}
232
233/* timer events: mode1 and mode2 */
234static int
235timing_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
236{
237 switch (q->t.cmd) {
238 case TMR_ECHO:
239 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
240 return set_echo_event(dp, q, ev);
241 else {
242 evrec_t tmp;
243 memset(&tmp, 0, sizeof(tmp));
244 /* XXX: only for little-endian! */
245 tmp.echo = (q->t.time << 8) | SEQ_ECHO;
246 return set_echo_event(dp, &tmp, ev);
247 }
248
249 case TMR_STOP:
250 if (dp->seq_mode)
251 return snd_seq_oss_timer_stop(dp->timer);
252 return 0;
253
254 case TMR_CONTINUE:
255 if (dp->seq_mode)
256 return snd_seq_oss_timer_continue(dp->timer);
257 return 0;
258
259 case TMR_TEMPO:
260 if (dp->seq_mode)
261 return snd_seq_oss_timer_tempo(dp->timer, q->t.time);
262 return 0;
263 }
264
265 return -EINVAL;
266}
267
268/* local events: mode1 and 2 */
269static int
270local_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev)
271{
272 return -EINVAL;
273}
274
275/*
276 * process note-on event for OSS synth
277 * three different modes are available:
278 * - SNDRV_SEQ_OSS_PROCESS_EVENTS (for one-voice per channel mode)
279 * Accept note 255 as volume change.
280 * - SNDRV_SEQ_OSS_PASS_EVENTS
281 * Pass all events to lowlevel driver anyway
282 * - SNDRV_SEQ_OSS_PROCESS_KEYPRESS (mostly for Emu8000)
283 * Use key-pressure if note >= 128
284 */
285static int
286note_on_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev)
287{
288 seq_oss_synthinfo_t *info = &dp->synths[dev];
289 switch (info->arg.event_passing) {
290 case SNDRV_SEQ_OSS_PROCESS_EVENTS:
291 if (! info->ch || ch < 0 || ch >= info->nr_voices) {
292 /* pass directly */
293 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
294 }
295
296 if (note == 255 && info->ch[ch].note >= 0) {
297 /* volume control */
298 int type;
299 //if (! vel)
300 /* set volume to zero -- note off */
301 // type = SNDRV_SEQ_EVENT_NOTEOFF;
302 //else
303 if (info->ch[ch].vel)
304 /* sample already started -- volume change */
305 type = SNDRV_SEQ_EVENT_KEYPRESS;
306 else
307 /* sample not started -- start now */
308 type = SNDRV_SEQ_EVENT_NOTEON;
309 info->ch[ch].vel = vel;
310 return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev);
311 } else if (note >= 128)
312 return -EINVAL; /* invalid */
313
314 if (note != info->ch[ch].note && info->ch[ch].note >= 0)
315 /* note changed - note off at beginning */
316 set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, info->ch[ch].note, 0, ev);
317 /* set current status */
318 info->ch[ch].note = note;
319 info->ch[ch].vel = vel;
320 if (vel) /* non-zero velocity - start the note now */
321 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
322 return -EINVAL;
323
324 case SNDRV_SEQ_OSS_PASS_EVENTS:
325 /* pass the event anyway */
326 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
327
328 case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
329 if (note >= 128) /* key pressure: shifted by 128 */
330 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_KEYPRESS, ch, note - 128, vel, ev);
331 else /* normal note-on event */
332 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
333 }
334 return -EINVAL;
335}
336
337/*
338 * process note-off event for OSS synth
339 */
340static int
341note_off_event(seq_oss_devinfo_t *dp, int dev, int ch, int note, int vel, snd_seq_event_t *ev)
342{
343 seq_oss_synthinfo_t *info = &dp->synths[dev];
344 switch (info->arg.event_passing) {
345 case SNDRV_SEQ_OSS_PROCESS_EVENTS:
346 if (! info->ch || ch < 0 || ch >= info->nr_voices) {
347 /* pass directly */
348 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev);
349 }
350
351 if (info->ch[ch].note >= 0) {
352 note = info->ch[ch].note;
353 info->ch[ch].vel = 0;
354 info->ch[ch].note = -1;
355 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
356 }
357 return -EINVAL; /* invalid */
358
359 case SNDRV_SEQ_OSS_PASS_EVENTS:
360 case SNDRV_SEQ_OSS_PROCESS_KEYPRESS:
361 /* pass the event anyway */
362 return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEOFF, ch, note, vel, ev);
363
364 }
365 return -EINVAL;
366}
367
368/*
369 * create a note event
370 */
371static int
372set_note_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int note, int vel, snd_seq_event_t *ev)
373{
374 if (! snd_seq_oss_synth_is_valid(dp, dev))
375 return -ENXIO;
376
377 ev->type = type;
378 snd_seq_oss_synth_addr(dp, dev, ev);
379 ev->data.note.channel = ch;
380 ev->data.note.note = note;
381 ev->data.note.velocity = vel;
382
383 return 0;
384}
385
386/*
387 * create a control event
388 */
389static int
390set_control_event(seq_oss_devinfo_t *dp, int dev, int type, int ch, int param, int val, snd_seq_event_t *ev)
391{
392 if (! snd_seq_oss_synth_is_valid(dp, dev))
393 return -ENXIO;
394
395 ev->type = type;
396 snd_seq_oss_synth_addr(dp, dev, ev);
397 ev->data.control.channel = ch;
398 ev->data.control.param = param;
399 ev->data.control.value = val;
400
401 return 0;
402}
403
404/*
405 * create an echo event
406 */
407static int
408set_echo_event(seq_oss_devinfo_t *dp, evrec_t *rec, snd_seq_event_t *ev)
409{
410 ev->type = SNDRV_SEQ_EVENT_ECHO;
411 /* echo back to itself */
412 snd_seq_oss_fill_addr(dp, ev, dp->addr.client, dp->addr.port);
413 memcpy(&ev->data, rec, LONG_EVENT_SIZE);
414 return 0;
415}
416
417/*
418 * event input callback from ALSA sequencer:
419 * the echo event is processed here.
420 */
421int
422snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data,
423 int atomic, int hop)
424{
425 seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private_data;
426 evrec_t *rec;
427
428 if (ev->type != SNDRV_SEQ_EVENT_ECHO)
429 return snd_seq_oss_midi_input(ev, direct, private_data);
430
431 if (ev->source.client != dp->cseq)
432 return 0; /* ignored */
433
434 rec = (evrec_t*)&ev->data;
435 if (rec->s.code == SEQ_SYNCTIMER) {
436 /* sync echo back */
437 snd_seq_oss_writeq_wakeup(dp->writeq, rec->t.time);
438
439 } else {
440 /* echo back event */
441 if (dp->readq == NULL)
442 return 0;
443 snd_seq_oss_readq_put_event(dp->readq, rec);
444 }
445 return 0;
446}
447
diff --git a/sound/core/seq/oss/seq_oss_event.h b/sound/core/seq/oss/seq_oss_event.h
new file mode 100644
index 000000000000..bf1d4d3f53c9
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_event.h
@@ -0,0 +1,112 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * seq_oss_event.h - OSS event queue record
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SEQ_OSS_EVENT_H
24#define __SEQ_OSS_EVENT_H
25
26#include "seq_oss_device.h"
27
28#define SHORT_EVENT_SIZE 4
29#define LONG_EVENT_SIZE 8
30
31/* short event (4bytes) */
32typedef struct evrec_short_t {
33 unsigned char code;
34 unsigned char parm1;
35 unsigned char dev;
36 unsigned char parm2;
37} evrec_short_t;
38
39/* short note events (4bytes) */
40typedef struct evrec_note_t {
41 unsigned char code;
42 unsigned char chn;
43 unsigned char note;
44 unsigned char vel;
45} evrec_note_t;
46
47/* long timer events (8bytes) */
48typedef struct evrec_timer_t {
49 unsigned char code;
50 unsigned char cmd;
51 unsigned char dummy1, dummy2;
52 unsigned int time;
53} evrec_timer_t;
54
55/* long extended events (8bytes) */
56typedef struct evrec_extended_t {
57 unsigned char code;
58 unsigned char cmd;
59 unsigned char dev;
60 unsigned char chn;
61 unsigned char p1, p2, p3, p4;
62} evrec_extended_t;
63
64/* long channel events (8bytes) */
65typedef struct evrec_long_t {
66 unsigned char code;
67 unsigned char dev;
68 unsigned char cmd;
69 unsigned char chn;
70 unsigned char p1, p2;
71 unsigned short val;
72} evrec_long_t;
73
74/* channel voice events (8bytes) */
75typedef struct evrec_voice_t {
76 unsigned char code;
77 unsigned char dev;
78 unsigned char cmd;
79 unsigned char chn;
80 unsigned char note, parm;
81 unsigned short dummy;
82} evrec_voice_t;
83
84/* sysex events (8bytes) */
85typedef struct evrec_sysex_t {
86 unsigned char code;
87 unsigned char dev;
88 unsigned char buf[6];
89} evrec_sysex_t;
90
91/* event record */
92union evrec_t {
93 evrec_short_t s;
94 evrec_note_t n;
95 evrec_long_t l;
96 evrec_voice_t v;
97 evrec_timer_t t;
98 evrec_extended_t e;
99 evrec_sysex_t x;
100 unsigned int echo;
101 unsigned char c[LONG_EVENT_SIZE];
102};
103
104#define ev_is_long(ev) ((ev)->s.code >= 128)
105#define ev_length(ev) ((ev)->s.code >= 128 ? LONG_EVENT_SIZE : SHORT_EVENT_SIZE)
106
107int snd_seq_oss_process_event(seq_oss_devinfo_t *dp, evrec_t *q, snd_seq_event_t *ev);
108int snd_seq_oss_process_timer_event(seq_oss_timer_t *rec, evrec_t *q);
109int snd_seq_oss_event_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop);
110
111
112#endif /* __SEQ_OSS_EVENT_H */
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
new file mode 100644
index 000000000000..bac4b4f1a94e
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -0,0 +1,555 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * open/close and reset interface
5 *
6 * Copyright (C) 1998-1999 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_device.h"
24#include "seq_oss_synth.h"
25#include "seq_oss_midi.h"
26#include "seq_oss_writeq.h"
27#include "seq_oss_readq.h"
28#include "seq_oss_timer.h"
29#include "seq_oss_event.h"
30#include <linux/init.h>
31#include <linux/moduleparam.h>
32
33/*
34 * common variables
35 */
36static int maxqlen = SNDRV_SEQ_OSS_MAX_QLEN;
37module_param(maxqlen, int, 0444);
38MODULE_PARM_DESC(maxqlen, "maximum queue length");
39
40static int system_client = -1; /* ALSA sequencer client number */
41static int system_port = -1;
42
43static int num_clients;
44static seq_oss_devinfo_t *client_table[SNDRV_SEQ_OSS_MAX_CLIENTS];
45
46
47/*
48 * prototypes
49 */
50static int receive_announce(snd_seq_event_t *ev, int direct, void *private, int atomic, int hop);
51static int translate_mode(struct file *file);
52static int create_port(seq_oss_devinfo_t *dp);
53static int delete_port(seq_oss_devinfo_t *dp);
54static int alloc_seq_queue(seq_oss_devinfo_t *dp);
55static int delete_seq_queue(int queue);
56static void free_devinfo(void *private);
57
58#define call_ctl(type,rec) snd_seq_kernel_client_ctl(system_client, type, rec)
59
60
61/*
62 * create sequencer client for OSS sequencer
63 */
64int __init
65snd_seq_oss_create_client(void)
66{
67 int rc;
68 snd_seq_client_callback_t callback;
69 snd_seq_client_info_t *info;
70 snd_seq_port_info_t *port;
71 snd_seq_port_callback_t port_callback;
72
73 info = kmalloc(sizeof(*info), GFP_KERNEL);
74 port = kmalloc(sizeof(*port), GFP_KERNEL);
75 if (!info || !port) {
76 rc = -ENOMEM;
77 goto __error;
78 }
79
80 /* create ALSA client */
81 memset(&callback, 0, sizeof(callback));
82
83 callback.private_data = NULL;
84 callback.allow_input = 1;
85 callback.allow_output = 1;
86
87 rc = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_OSS, &callback);
88 if (rc < 0)
89 goto __error;
90
91 system_client = rc;
92 debug_printk(("new client = %d\n", rc));
93
94 /* set client information */
95 memset(info, 0, sizeof(*info));
96 info->client = system_client;
97 info->type = KERNEL_CLIENT;
98 strcpy(info->name, "OSS sequencer");
99
100 rc = call_ctl(SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, info);
101
102 /* look up midi devices */
103 snd_seq_oss_midi_lookup_ports(system_client);
104
105 /* create annoucement receiver port */
106 memset(port, 0, sizeof(*port));
107 strcpy(port->name, "Receiver");
108 port->addr.client = system_client;
109 port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* receive only */
110 port->type = 0;
111
112 memset(&port_callback, 0, sizeof(port_callback));
113 /* don't set port_callback.owner here. otherwise the module counter
114 * is incremented and we can no longer release the module..
115 */
116 port_callback.event_input = receive_announce;
117 port->kernel = &port_callback;
118
119 call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
120 if ((system_port = port->addr.port) >= 0) {
121 snd_seq_port_subscribe_t subs;
122
123 memset(&subs, 0, sizeof(subs));
124 subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
125 subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
126 subs.dest.client = system_client;
127 subs.dest.port = system_port;
128 call_ctl(SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs);
129 }
130 rc = 0;
131
132 __error:
133 kfree(port);
134 kfree(info);
135 return rc;
136}
137
138
139/*
140 * receive annoucement from system port, and check the midi device
141 */
142static int
143receive_announce(snd_seq_event_t *ev, int direct, void *private, int atomic, int hop)
144{
145 snd_seq_port_info_t pinfo;
146
147 if (atomic)
148 return 0; /* it must not happen */
149
150 switch (ev->type) {
151 case SNDRV_SEQ_EVENT_PORT_START:
152 case SNDRV_SEQ_EVENT_PORT_CHANGE:
153 if (ev->data.addr.client == system_client)
154 break; /* ignore myself */
155 memset(&pinfo, 0, sizeof(pinfo));
156 pinfo.addr = ev->data.addr;
157 if (call_ctl(SNDRV_SEQ_IOCTL_GET_PORT_INFO, &pinfo) >= 0)
158 snd_seq_oss_midi_check_new_port(&pinfo);
159 break;
160
161 case SNDRV_SEQ_EVENT_PORT_EXIT:
162 if (ev->data.addr.client == system_client)
163 break; /* ignore myself */
164 snd_seq_oss_midi_check_exit_port(ev->data.addr.client,
165 ev->data.addr.port);
166 break;
167 }
168 return 0;
169}
170
171
172/*
173 * delete OSS sequencer client
174 */
175int
176snd_seq_oss_delete_client(void)
177{
178 if (system_client >= 0)
179 snd_seq_delete_kernel_client(system_client);
180
181 snd_seq_oss_midi_clear_all();
182
183 return 0;
184}
185
186
187/*
188 * open sequencer device
189 */
190int
191snd_seq_oss_open(struct file *file, int level)
192{
193 int i, rc;
194 seq_oss_devinfo_t *dp;
195
196 if ((dp = kcalloc(1, sizeof(*dp), GFP_KERNEL)) == NULL) {
197 snd_printk(KERN_ERR "can't malloc device info\n");
198 return -ENOMEM;
199 }
200 debug_printk(("oss_open: dp = %p\n", dp));
201
202 for (i = 0; i < SNDRV_SEQ_OSS_MAX_CLIENTS; i++) {
203 if (client_table[i] == NULL)
204 break;
205 }
206 if (i >= SNDRV_SEQ_OSS_MAX_CLIENTS) {
207 snd_printk(KERN_ERR "too many applications\n");
208 kfree(dp);
209 return -ENOMEM;
210 }
211
212 dp->index = i;
213 dp->cseq = system_client;
214 dp->port = -1;
215 dp->queue = -1;
216 dp->readq = NULL;
217 dp->writeq = NULL;
218
219 /* look up synth and midi devices */
220 snd_seq_oss_synth_setup(dp);
221 snd_seq_oss_midi_setup(dp);
222
223 if (dp->synth_opened == 0 && dp->max_mididev == 0) {
224 /* snd_printk(KERN_ERR "no device found\n"); */
225 rc = -ENODEV;
226 goto _error;
227 }
228
229 /* create port */
230 debug_printk(("create new port\n"));
231 if ((rc = create_port(dp)) < 0) {
232 snd_printk(KERN_ERR "can't create port\n");
233 goto _error;
234 }
235
236 /* allocate queue */
237 debug_printk(("allocate queue\n"));
238 if ((rc = alloc_seq_queue(dp)) < 0)
239 goto _error;
240
241 /* set address */
242 dp->addr.client = dp->cseq;
243 dp->addr.port = dp->port;
244 /*dp->addr.queue = dp->queue;*/
245 /*dp->addr.channel = 0;*/
246
247 dp->seq_mode = level;
248
249 /* set up file mode */
250 dp->file_mode = translate_mode(file);
251
252 /* initialize read queue */
253 debug_printk(("initialize read queue\n"));
254 if (is_read_mode(dp->file_mode)) {
255 if ((dp->readq = snd_seq_oss_readq_new(dp, maxqlen)) == NULL) {
256 rc = -ENOMEM;
257 goto _error;
258 }
259 }
260
261 /* initialize write queue */
262 debug_printk(("initialize write queue\n"));
263 if (is_write_mode(dp->file_mode)) {
264 dp->writeq = snd_seq_oss_writeq_new(dp, maxqlen);
265 if (dp->writeq == NULL) {
266 rc = -ENOMEM;
267 goto _error;
268 }
269 }
270
271 /* initialize timer */
272 debug_printk(("initialize timer\n"));
273 if ((dp->timer = snd_seq_oss_timer_new(dp)) == NULL) {
274 snd_printk(KERN_ERR "can't alloc timer\n");
275 rc = -ENOMEM;
276 goto _error;
277 }
278 debug_printk(("timer initialized\n"));
279
280 /* set private data pointer */
281 file->private_data = dp;
282
283 /* set up for mode2 */
284 if (level == SNDRV_SEQ_OSS_MODE_MUSIC)
285 snd_seq_oss_synth_setup_midi(dp);
286 else if (is_read_mode(dp->file_mode))
287 snd_seq_oss_midi_open_all(dp, SNDRV_SEQ_OSS_FILE_READ);
288
289 client_table[dp->index] = dp;
290 num_clients++;
291
292 debug_printk(("open done\n"));
293 return 0;
294
295 _error:
296 snd_seq_oss_synth_cleanup(dp);
297 snd_seq_oss_midi_cleanup(dp);
298 i = dp->queue;
299 delete_port(dp);
300 delete_seq_queue(i);
301
302 return rc;
303}
304
305/*
306 * translate file flags to private mode
307 */
308static int
309translate_mode(struct file *file)
310{
311 int file_mode = 0;
312 if ((file->f_flags & O_ACCMODE) != O_RDONLY)
313 file_mode |= SNDRV_SEQ_OSS_FILE_WRITE;
314 if ((file->f_flags & O_ACCMODE) != O_WRONLY)
315 file_mode |= SNDRV_SEQ_OSS_FILE_READ;
316 if (file->f_flags & O_NONBLOCK)
317 file_mode |= SNDRV_SEQ_OSS_FILE_NONBLOCK;
318 return file_mode;
319}
320
321
322/*
323 * create sequencer port
324 */
325static int
326create_port(seq_oss_devinfo_t *dp)
327{
328 int rc;
329 snd_seq_port_info_t port;
330 snd_seq_port_callback_t callback;
331
332 memset(&port, 0, sizeof(port));
333 port.addr.client = dp->cseq;
334 sprintf(port.name, "Sequencer-%d", dp->index);
335 port.capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_WRITE; /* no subscription */
336 port.type = SNDRV_SEQ_PORT_TYPE_SPECIFIC;
337 port.midi_channels = 128;
338 port.synth_voices = 128;
339
340 memset(&callback, 0, sizeof(callback));
341 callback.owner = THIS_MODULE;
342 callback.private_data = dp;
343 callback.event_input = snd_seq_oss_event_input;
344 callback.private_free = free_devinfo;
345 port.kernel = &callback;
346
347 rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, &port);
348 if (rc < 0)
349 return rc;
350
351 dp->port = port.addr.port;
352 debug_printk(("new port = %d\n", port.addr.port));
353
354 return 0;
355}
356
357/*
358 * delete ALSA port
359 */
360static int
361delete_port(seq_oss_devinfo_t *dp)
362{
363 if (dp->port < 0)
364 return 0;
365
366 debug_printk(("delete_port %i\n", dp->port));
367 return snd_seq_event_port_detach(dp->cseq, dp->port);
368}
369
370/*
371 * allocate a queue
372 */
373static int
374alloc_seq_queue(seq_oss_devinfo_t *dp)
375{
376 snd_seq_queue_info_t qinfo;
377 int rc;
378
379 memset(&qinfo, 0, sizeof(qinfo));
380 qinfo.owner = system_client;
381 qinfo.locked = 1;
382 strcpy(qinfo.name, "OSS Sequencer Emulation");
383 if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0)
384 return rc;
385 dp->queue = qinfo.queue;
386 return 0;
387}
388
389/*
390 * release queue
391 */
392static int
393delete_seq_queue(int queue)
394{
395 snd_seq_queue_info_t qinfo;
396 int rc;
397
398 if (queue < 0)
399 return 0;
400 memset(&qinfo, 0, sizeof(qinfo));
401 qinfo.queue = queue;
402 rc = call_ctl(SNDRV_SEQ_IOCTL_DELETE_QUEUE, &qinfo);
403 if (rc < 0)
404 printk(KERN_ERR "seq-oss: unable to delete queue %d (%d)\n", queue, rc);
405 return rc;
406}
407
408
409/*
410 * free device informations - private_free callback of port
411 */
412static void
413free_devinfo(void *private)
414{
415 seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private;
416
417 if (dp->timer)
418 snd_seq_oss_timer_delete(dp->timer);
419
420 if (dp->writeq)
421 snd_seq_oss_writeq_delete(dp->writeq);
422
423 if (dp->readq)
424 snd_seq_oss_readq_delete(dp->readq);
425
426 kfree(dp);
427}
428
429
430/*
431 * close sequencer device
432 */
433void
434snd_seq_oss_release(seq_oss_devinfo_t *dp)
435{
436 int queue;
437
438 client_table[dp->index] = NULL;
439 num_clients--;
440
441 debug_printk(("resetting..\n"));
442 snd_seq_oss_reset(dp);
443
444 debug_printk(("cleaning up..\n"));
445 snd_seq_oss_synth_cleanup(dp);
446 snd_seq_oss_midi_cleanup(dp);
447
448 /* clear slot */
449 debug_printk(("releasing resource..\n"));
450 queue = dp->queue;
451 if (dp->port >= 0)
452 delete_port(dp);
453 delete_seq_queue(queue);
454
455 debug_printk(("release done\n"));
456}
457
458
459/*
460 * Wait until the queue is empty (if we don't have nonblock)
461 */
462void
463snd_seq_oss_drain_write(seq_oss_devinfo_t *dp)
464{
465 if (! dp->timer->running)
466 return;
467 if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
468 dp->writeq) {
469 debug_printk(("syncing..\n"));
470 while (snd_seq_oss_writeq_sync(dp->writeq))
471 ;
472 }
473}
474
475
476/*
477 * reset sequencer devices
478 */
479void
480snd_seq_oss_reset(seq_oss_devinfo_t *dp)
481{
482 int i;
483
484 /* reset all synth devices */
485 for (i = 0; i < dp->max_synthdev; i++)
486 snd_seq_oss_synth_reset(dp, i);
487
488 /* reset all midi devices */
489 if (dp->seq_mode != SNDRV_SEQ_OSS_MODE_MUSIC) {
490 for (i = 0; i < dp->max_mididev; i++)
491 snd_seq_oss_midi_reset(dp, i);
492 }
493
494 /* remove queues */
495 if (dp->readq)
496 snd_seq_oss_readq_clear(dp->readq);
497 if (dp->writeq)
498 snd_seq_oss_writeq_clear(dp->writeq);
499
500 /* reset timer */
501 snd_seq_oss_timer_stop(dp->timer);
502}
503
504
505/*
506 * misc. functions for proc interface
507 */
508char *
509enabled_str(int bool)
510{
511 return bool ? "enabled" : "disabled";
512}
513
514static char *
515filemode_str(int val)
516{
517 static char *str[] = {
518 "none", "read", "write", "read/write",
519 };
520 return str[val & SNDRV_SEQ_OSS_FILE_ACMODE];
521}
522
523
524/*
525 * proc interface
526 */
527void
528snd_seq_oss_system_info_read(snd_info_buffer_t *buf)
529{
530 int i;
531 seq_oss_devinfo_t *dp;
532
533 snd_iprintf(buf, "ALSA client number %d\n", system_client);
534 snd_iprintf(buf, "ALSA receiver port %d\n", system_port);
535
536 snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
537 for (i = 0; i < num_clients; i++) {
538 snd_iprintf(buf, "\nApplication %d: ", i);
539 if ((dp = client_table[i]) == NULL) {
540 snd_iprintf(buf, "*empty*\n");
541 continue;
542 }
543 snd_iprintf(buf, "port %d : queue %d\n", dp->port, dp->queue);
544 snd_iprintf(buf, " sequencer mode = %s : file open mode = %s\n",
545 (dp->seq_mode ? "music" : "synth"),
546 filemode_str(dp->file_mode));
547 if (dp->seq_mode)
548 snd_iprintf(buf, " timer tempo = %d, timebase = %d\n",
549 dp->timer->oss_tempo, dp->timer->oss_timebase);
550 snd_iprintf(buf, " max queue length %d\n", maxqlen);
551 if (is_read_mode(dp->file_mode) && dp->readq)
552 snd_seq_oss_readq_info_read(dp->readq, buf);
553 }
554}
555
diff --git a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
new file mode 100644
index 000000000000..e86f18d00f39
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_ioctl.c
@@ -0,0 +1,209 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * OSS compatible i/o control
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_device.h"
24#include "seq_oss_readq.h"
25#include "seq_oss_writeq.h"
26#include "seq_oss_timer.h"
27#include "seq_oss_synth.h"
28#include "seq_oss_midi.h"
29#include "seq_oss_event.h"
30
31static int snd_seq_oss_synth_info_user(seq_oss_devinfo_t *dp, void __user *arg)
32{
33 struct synth_info info;
34
35 if (copy_from_user(&info, arg, sizeof(info)))
36 return -EFAULT;
37 if (snd_seq_oss_synth_make_info(dp, info.device, &info) < 0)
38 return -EINVAL;
39 if (copy_to_user(arg, &info, sizeof(info)))
40 return -EFAULT;
41 return 0;
42}
43
44static int snd_seq_oss_midi_info_user(seq_oss_devinfo_t *dp, void __user *arg)
45{
46 struct midi_info info;
47
48 if (copy_from_user(&info, arg, sizeof(info)))
49 return -EFAULT;
50 if (snd_seq_oss_midi_make_info(dp, info.device, &info) < 0)
51 return -EINVAL;
52 if (copy_to_user(arg, &info, sizeof(info)))
53 return -EFAULT;
54 return 0;
55}
56
57static int snd_seq_oss_oob_user(seq_oss_devinfo_t *dp, void __user *arg)
58{
59 unsigned char ev[8];
60 snd_seq_event_t tmpev;
61
62 if (copy_from_user(ev, arg, 8))
63 return -EFAULT;
64 memset(&tmpev, 0, sizeof(tmpev));
65 snd_seq_oss_fill_addr(dp, &tmpev, dp->addr.port, dp->addr.client);
66 tmpev.time.tick = 0;
67 if (! snd_seq_oss_process_event(dp, (evrec_t*)ev, &tmpev)) {
68 snd_seq_oss_dispatch(dp, &tmpev, 0, 0);
69 }
70 return 0;
71}
72
73int
74snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long carg)
75{
76 int dev, val;
77 void __user *arg = (void __user *)carg;
78 int __user *p = arg;
79
80 switch (cmd) {
81 case SNDCTL_TMR_TIMEBASE:
82 case SNDCTL_TMR_TEMPO:
83 case SNDCTL_TMR_START:
84 case SNDCTL_TMR_STOP:
85 case SNDCTL_TMR_CONTINUE:
86 case SNDCTL_TMR_METRONOME:
87 case SNDCTL_TMR_SOURCE:
88 case SNDCTL_TMR_SELECT:
89 case SNDCTL_SEQ_CTRLRATE:
90 return snd_seq_oss_timer_ioctl(dp->timer, cmd, arg);
91
92 case SNDCTL_SEQ_PANIC:
93 debug_printk(("panic\n"));
94 snd_seq_oss_reset(dp);
95 return -EINVAL;
96
97 case SNDCTL_SEQ_SYNC:
98 debug_printk(("sync\n"));
99 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
100 return 0;
101 while (snd_seq_oss_writeq_sync(dp->writeq))
102 ;
103 if (signal_pending(current))
104 return -ERESTARTSYS;
105 return 0;
106
107 case SNDCTL_SEQ_RESET:
108 debug_printk(("reset\n"));
109 snd_seq_oss_reset(dp);
110 return 0;
111
112 case SNDCTL_SEQ_TESTMIDI:
113 debug_printk(("test midi\n"));
114 if (get_user(dev, p))
115 return -EFAULT;
116 return snd_seq_oss_midi_open(dp, dev, dp->file_mode);
117
118 case SNDCTL_SEQ_GETINCOUNT:
119 debug_printk(("get in count\n"));
120 if (dp->readq == NULL || ! is_read_mode(dp->file_mode))
121 return 0;
122 return put_user(dp->readq->qlen, p) ? -EFAULT : 0;
123
124 case SNDCTL_SEQ_GETOUTCOUNT:
125 debug_printk(("get out count\n"));
126 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
127 return 0;
128 return put_user(snd_seq_oss_writeq_get_free_size(dp->writeq), p) ? -EFAULT : 0;
129
130 case SNDCTL_SEQ_GETTIME:
131 debug_printk(("get time\n"));
132 return put_user(snd_seq_oss_timer_cur_tick(dp->timer), p) ? -EFAULT : 0;
133
134 case SNDCTL_SEQ_RESETSAMPLES:
135 debug_printk(("reset samples\n"));
136 if (get_user(dev, p))
137 return -EFAULT;
138 return snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
139
140 case SNDCTL_SEQ_NRSYNTHS:
141 debug_printk(("nr synths\n"));
142 return put_user(dp->max_synthdev, p) ? -EFAULT : 0;
143
144 case SNDCTL_SEQ_NRMIDIS:
145 debug_printk(("nr midis\n"));
146 return put_user(dp->max_mididev, p) ? -EFAULT : 0;
147
148 case SNDCTL_SYNTH_MEMAVL:
149 debug_printk(("mem avail\n"));
150 if (get_user(dev, p))
151 return -EFAULT;
152 val = snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
153 return put_user(val, p) ? -EFAULT : 0;
154
155 case SNDCTL_FM_4OP_ENABLE:
156 debug_printk(("4op\n"));
157 if (get_user(dev, p))
158 return -EFAULT;
159 snd_seq_oss_synth_ioctl(dp, dev, cmd, carg);
160 return 0;
161
162 case SNDCTL_SYNTH_INFO:
163 case SNDCTL_SYNTH_ID:
164 debug_printk(("synth info\n"));
165 return snd_seq_oss_synth_info_user(dp, arg);
166
167 case SNDCTL_SEQ_OUTOFBAND:
168 debug_printk(("out of band\n"));
169 return snd_seq_oss_oob_user(dp, arg);
170
171 case SNDCTL_MIDI_INFO:
172 debug_printk(("midi info\n"));
173 return snd_seq_oss_midi_info_user(dp, arg);
174
175 case SNDCTL_SEQ_THRESHOLD:
176 debug_printk(("threshold\n"));
177 if (! is_write_mode(dp->file_mode))
178 return 0;
179 if (get_user(val, p))
180 return -EFAULT;
181 if (val < 1)
182 val = 1;
183 if (val >= dp->writeq->maxlen)
184 val = dp->writeq->maxlen - 1;
185 snd_seq_oss_writeq_set_output(dp->writeq, val);
186 return 0;
187
188 case SNDCTL_MIDI_PRETIME:
189 debug_printk(("pretime\n"));
190 if (dp->readq == NULL || !is_read_mode(dp->file_mode))
191 return 0;
192 if (get_user(val, p))
193 return -EFAULT;
194 if (val <= 0)
195 val = -1;
196 else
197 val = (HZ * val) / 10;
198 dp->readq->pre_event_timeout = val;
199 return put_user(val, p) ? -EFAULT : 0;
200
201 default:
202 debug_printk(("others\n"));
203 if (! is_write_mode(dp->file_mode))
204 return -EIO;
205 return snd_seq_oss_synth_ioctl(dp, 0, cmd, carg);
206 }
207 return 0;
208}
209
diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
new file mode 100644
index 000000000000..9aece6c65dbc
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_midi.c
@@ -0,0 +1,710 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * MIDI device handlers
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_midi.h"
24#include "seq_oss_readq.h"
25#include "seq_oss_timer.h"
26#include "seq_oss_event.h"
27#include <sound/seq_midi_event.h>
28#include "../seq_lock.h"
29#include <linux/init.h>
30
31
32/*
33 * constants
34 */
35#define SNDRV_SEQ_OSS_MAX_MIDI_NAME 30
36
37/*
38 * definition of midi device record
39 */
40struct seq_oss_midi_t {
41 int seq_device; /* device number */
42 int client; /* sequencer client number */
43 int port; /* sequencer port number */
44 unsigned int flags; /* port capability */
45 int opened; /* flag for opening */
46 unsigned char name[SNDRV_SEQ_OSS_MAX_MIDI_NAME];
47 snd_midi_event_t *coder; /* MIDI event coder */
48 seq_oss_devinfo_t *devinfo; /* assigned OSSseq device */
49 snd_use_lock_t use_lock;
50};
51
52
53/*
54 * midi device table
55 */
56static int max_midi_devs;
57static seq_oss_midi_t *midi_devs[SNDRV_SEQ_OSS_MAX_MIDI_DEVS];
58
59static DEFINE_SPINLOCK(register_lock);
60
61/*
62 * prototypes
63 */
64static seq_oss_midi_t *get_mdev(int dev);
65static seq_oss_midi_t *get_mididev(seq_oss_devinfo_t *dp, int dev);
66static int send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev);
67static int send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev);
68
69/*
70 * look up the existing ports
71 * this looks a very exhausting job.
72 */
73int __init
74snd_seq_oss_midi_lookup_ports(int client)
75{
76 snd_seq_client_info_t *clinfo;
77 snd_seq_port_info_t *pinfo;
78
79 clinfo = kcalloc(1, sizeof(*clinfo), GFP_KERNEL);
80 pinfo = kcalloc(1, sizeof(*pinfo), GFP_KERNEL);
81 if (! clinfo || ! pinfo) {
82 kfree(clinfo);
83 kfree(pinfo);
84 return -ENOMEM;
85 }
86 clinfo->client = -1;
87 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, clinfo) == 0) {
88 if (clinfo->client == client)
89 continue; /* ignore myself */
90 pinfo->addr.client = clinfo->client;
91 pinfo->addr.port = -1;
92 while (snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, pinfo) == 0)
93 snd_seq_oss_midi_check_new_port(pinfo);
94 }
95 kfree(clinfo);
96 kfree(pinfo);
97 return 0;
98}
99
100
101/*
102 */
103static seq_oss_midi_t *
104get_mdev(int dev)
105{
106 seq_oss_midi_t *mdev;
107 unsigned long flags;
108
109 spin_lock_irqsave(&register_lock, flags);
110 mdev = midi_devs[dev];
111 if (mdev)
112 snd_use_lock_use(&mdev->use_lock);
113 spin_unlock_irqrestore(&register_lock, flags);
114 return mdev;
115}
116
117/*
118 * look for the identical slot
119 */
120static seq_oss_midi_t *
121find_slot(int client, int port)
122{
123 int i;
124 seq_oss_midi_t *mdev;
125 unsigned long flags;
126
127 spin_lock_irqsave(&register_lock, flags);
128 for (i = 0; i < max_midi_devs; i++) {
129 mdev = midi_devs[i];
130 if (mdev && mdev->client == client && mdev->port == port) {
131 /* found! */
132 snd_use_lock_use(&mdev->use_lock);
133 spin_unlock_irqrestore(&register_lock, flags);
134 return mdev;
135 }
136 }
137 spin_unlock_irqrestore(&register_lock, flags);
138 return NULL;
139}
140
141
142#define PERM_WRITE (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
143#define PERM_READ (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
144/*
145 * register a new port if it doesn't exist yet
146 */
147int
148snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo)
149{
150 int i;
151 seq_oss_midi_t *mdev;
152 unsigned long flags;
153
154 debug_printk(("check for MIDI client %d port %d\n", pinfo->addr.client, pinfo->addr.port));
155 /* the port must include generic midi */
156 if (! (pinfo->type & SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC))
157 return 0;
158 /* either read or write subscribable */
159 if ((pinfo->capability & PERM_WRITE) != PERM_WRITE &&
160 (pinfo->capability & PERM_READ) != PERM_READ)
161 return 0;
162
163 /*
164 * look for the identical slot
165 */
166 if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) {
167 /* already exists */
168 snd_use_lock_free(&mdev->use_lock);
169 return 0;
170 }
171
172 /*
173 * allocate midi info record
174 */
175 if ((mdev = kcalloc(1, sizeof(*mdev), GFP_KERNEL)) == NULL) {
176 snd_printk(KERN_ERR "can't malloc midi info\n");
177 return -ENOMEM;
178 }
179
180 /* copy the port information */
181 mdev->client = pinfo->addr.client;
182 mdev->port = pinfo->addr.port;
183 mdev->flags = pinfo->capability;
184 mdev->opened = 0;
185 snd_use_lock_init(&mdev->use_lock);
186
187 /* copy and truncate the name of synth device */
188 strlcpy(mdev->name, pinfo->name, sizeof(mdev->name));
189
190 /* create MIDI coder */
191 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &mdev->coder) < 0) {
192 snd_printk(KERN_ERR "can't malloc midi coder\n");
193 kfree(mdev);
194 return -ENOMEM;
195 }
196 /* OSS sequencer adds running status to all sequences */
197 snd_midi_event_no_status(mdev->coder, 1);
198
199 /*
200 * look for en empty slot
201 */
202 spin_lock_irqsave(&register_lock, flags);
203 for (i = 0; i < max_midi_devs; i++) {
204 if (midi_devs[i] == NULL)
205 break;
206 }
207 if (i >= max_midi_devs) {
208 if (max_midi_devs >= SNDRV_SEQ_OSS_MAX_MIDI_DEVS) {
209 spin_unlock_irqrestore(&register_lock, flags);
210 snd_midi_event_free(mdev->coder);
211 kfree(mdev);
212 return -ENOMEM;
213 }
214 max_midi_devs++;
215 }
216 mdev->seq_device = i;
217 midi_devs[mdev->seq_device] = mdev;
218 spin_unlock_irqrestore(&register_lock, flags);
219
220 return 0;
221}
222
223/*
224 * release the midi device if it was registered
225 */
226int
227snd_seq_oss_midi_check_exit_port(int client, int port)
228{
229 seq_oss_midi_t *mdev;
230 unsigned long flags;
231 int index;
232
233 if ((mdev = find_slot(client, port)) != NULL) {
234 spin_lock_irqsave(&register_lock, flags);
235 midi_devs[mdev->seq_device] = NULL;
236 spin_unlock_irqrestore(&register_lock, flags);
237 snd_use_lock_free(&mdev->use_lock);
238 snd_use_lock_sync(&mdev->use_lock);
239 if (mdev->coder)
240 snd_midi_event_free(mdev->coder);
241 kfree(mdev);
242 }
243 spin_lock_irqsave(&register_lock, flags);
244 for (index = max_midi_devs - 1; index >= 0; index--) {
245 if (midi_devs[index])
246 break;
247 }
248 max_midi_devs = index + 1;
249 spin_unlock_irqrestore(&register_lock, flags);
250 return 0;
251}
252
253
254/*
255 * release the midi device if it was registered
256 */
257void
258snd_seq_oss_midi_clear_all(void)
259{
260 int i;
261 seq_oss_midi_t *mdev;
262 unsigned long flags;
263
264 spin_lock_irqsave(&register_lock, flags);
265 for (i = 0; i < max_midi_devs; i++) {
266 if ((mdev = midi_devs[i]) != NULL) {
267 if (mdev->coder)
268 snd_midi_event_free(mdev->coder);
269 kfree(mdev);
270 midi_devs[i] = NULL;
271 }
272 }
273 max_midi_devs = 0;
274 spin_unlock_irqrestore(&register_lock, flags);
275}
276
277
278/*
279 * set up midi tables
280 */
281void
282snd_seq_oss_midi_setup(seq_oss_devinfo_t *dp)
283{
284 dp->max_mididev = max_midi_devs;
285}
286
287/*
288 * clean up midi tables
289 */
290void
291snd_seq_oss_midi_cleanup(seq_oss_devinfo_t *dp)
292{
293 int i;
294 for (i = 0; i < dp->max_mididev; i++)
295 snd_seq_oss_midi_close(dp, i);
296 dp->max_mididev = 0;
297}
298
299
300/*
301 * open all midi devices. ignore errors.
302 */
303void
304snd_seq_oss_midi_open_all(seq_oss_devinfo_t *dp, int file_mode)
305{
306 int i;
307 for (i = 0; i < dp->max_mididev; i++)
308 snd_seq_oss_midi_open(dp, i, file_mode);
309}
310
311
312/*
313 * get the midi device information
314 */
315static seq_oss_midi_t *
316get_mididev(seq_oss_devinfo_t *dp, int dev)
317{
318 if (dev < 0 || dev >= dp->max_mididev)
319 return NULL;
320 return get_mdev(dev);
321}
322
323
324/*
325 * open the midi device if not opened yet
326 */
327int
328snd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int fmode)
329{
330 int perm;
331 seq_oss_midi_t *mdev;
332 snd_seq_port_subscribe_t subs;
333
334 if ((mdev = get_mididev(dp, dev)) == NULL)
335 return -ENODEV;
336
337 /* already used? */
338 if (mdev->opened && mdev->devinfo != dp) {
339 snd_use_lock_free(&mdev->use_lock);
340 return -EBUSY;
341 }
342
343 perm = 0;
344 if (is_write_mode(fmode))
345 perm |= PERM_WRITE;
346 if (is_read_mode(fmode))
347 perm |= PERM_READ;
348 perm &= mdev->flags;
349 if (perm == 0) {
350 snd_use_lock_free(&mdev->use_lock);
351 return -ENXIO;
352 }
353
354 /* already opened? */
355 if ((mdev->opened & perm) == perm) {
356 snd_use_lock_free(&mdev->use_lock);
357 return 0;
358 }
359
360 perm &= ~mdev->opened;
361
362 memset(&subs, 0, sizeof(subs));
363
364 if (perm & PERM_WRITE) {
365 subs.sender = dp->addr;
366 subs.dest.client = mdev->client;
367 subs.dest.port = mdev->port;
368 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
369 mdev->opened |= PERM_WRITE;
370 }
371 if (perm & PERM_READ) {
372 subs.sender.client = mdev->client;
373 subs.sender.port = mdev->port;
374 subs.dest = dp->addr;
375 subs.flags = SNDRV_SEQ_PORT_SUBS_TIMESTAMP;
376 subs.queue = dp->queue; /* queue for timestamps */
377 if (snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, &subs) >= 0)
378 mdev->opened |= PERM_READ;
379 }
380
381 if (! mdev->opened) {
382 snd_use_lock_free(&mdev->use_lock);
383 return -ENXIO;
384 }
385
386 mdev->devinfo = dp;
387 snd_use_lock_free(&mdev->use_lock);
388 return 0;
389}
390
391/*
392 * close the midi device if already opened
393 */
394int
395snd_seq_oss_midi_close(seq_oss_devinfo_t *dp, int dev)
396{
397 seq_oss_midi_t *mdev;
398 snd_seq_port_subscribe_t subs;
399
400 if ((mdev = get_mididev(dp, dev)) == NULL)
401 return -ENODEV;
402 if (! mdev->opened || mdev->devinfo != dp) {
403 snd_use_lock_free(&mdev->use_lock);
404 return 0;
405 }
406
407 debug_printk(("closing client %d port %d mode %d\n", mdev->client, mdev->port, mdev->opened));
408 memset(&subs, 0, sizeof(subs));
409 if (mdev->opened & PERM_WRITE) {
410 subs.sender = dp->addr;
411 subs.dest.client = mdev->client;
412 subs.dest.port = mdev->port;
413 snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
414 }
415 if (mdev->opened & PERM_READ) {
416 subs.sender.client = mdev->client;
417 subs.sender.port = mdev->port;
418 subs.dest = dp->addr;
419 snd_seq_kernel_client_ctl(dp->cseq, SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, &subs);
420 }
421
422 mdev->opened = 0;
423 mdev->devinfo = NULL;
424
425 snd_use_lock_free(&mdev->use_lock);
426 return 0;
427}
428
429/*
430 * change seq capability flags to file mode flags
431 */
432int
433snd_seq_oss_midi_filemode(seq_oss_devinfo_t *dp, int dev)
434{
435 seq_oss_midi_t *mdev;
436 int mode;
437
438 if ((mdev = get_mididev(dp, dev)) == NULL)
439 return 0;
440
441 mode = 0;
442 if (mdev->opened & PERM_WRITE)
443 mode |= SNDRV_SEQ_OSS_FILE_WRITE;
444 if (mdev->opened & PERM_READ)
445 mode |= SNDRV_SEQ_OSS_FILE_READ;
446
447 snd_use_lock_free(&mdev->use_lock);
448 return mode;
449}
450
451/*
452 * reset the midi device and close it:
453 * so far, only close the device.
454 */
455void
456snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev)
457{
458 seq_oss_midi_t *mdev;
459
460 if ((mdev = get_mididev(dp, dev)) == NULL)
461 return;
462 if (! mdev->opened) {
463 snd_use_lock_free(&mdev->use_lock);
464 return;
465 }
466
467 if (mdev->opened & PERM_WRITE) {
468 snd_seq_event_t ev;
469 int c;
470
471 debug_printk(("resetting client %d port %d\n", mdev->client, mdev->port));
472 memset(&ev, 0, sizeof(ev));
473 ev.dest.client = mdev->client;
474 ev.dest.port = mdev->port;
475 ev.queue = dp->queue;
476 ev.source.port = dp->port;
477 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH) {
478 ev.type = SNDRV_SEQ_EVENT_SENSING;
479 snd_seq_oss_dispatch(dp, &ev, 0, 0); /* active sensing */
480 }
481 for (c = 0; c < 16; c++) {
482 ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
483 ev.data.control.channel = c;
484 ev.data.control.param = 123;
485 snd_seq_oss_dispatch(dp, &ev, 0, 0); /* all notes off */
486 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
487 ev.data.control.param = 121;
488 snd_seq_oss_dispatch(dp, &ev, 0, 0); /* reset all controllers */
489 ev.type = SNDRV_SEQ_EVENT_PITCHBEND;
490 ev.data.control.value = 0;
491 snd_seq_oss_dispatch(dp, &ev, 0, 0); /* bender off */
492 }
493 }
494 }
495 // snd_seq_oss_midi_close(dp, dev);
496 snd_use_lock_free(&mdev->use_lock);
497}
498
499
500/*
501 * get client/port of the specified MIDI device
502 */
503void
504snd_seq_oss_midi_get_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_addr_t *addr)
505{
506 seq_oss_midi_t *mdev;
507
508 if ((mdev = get_mididev(dp, dev)) == NULL)
509 return;
510 addr->client = mdev->client;
511 addr->port = mdev->port;
512 snd_use_lock_free(&mdev->use_lock);
513}
514
515
516/*
517 * input callback - this can be atomic
518 */
519int
520snd_seq_oss_midi_input(snd_seq_event_t *ev, int direct, void *private_data)
521{
522 seq_oss_devinfo_t *dp = (seq_oss_devinfo_t *)private_data;
523 seq_oss_midi_t *mdev;
524 int rc;
525
526 if (dp->readq == NULL)
527 return 0;
528 if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL)
529 return 0;
530 if (! (mdev->opened & PERM_READ)) {
531 snd_use_lock_free(&mdev->use_lock);
532 return 0;
533 }
534
535 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC)
536 rc = send_synth_event(dp, ev, mdev->seq_device);
537 else
538 rc = send_midi_event(dp, ev, mdev);
539
540 snd_use_lock_free(&mdev->use_lock);
541 return rc;
542}
543
544/*
545 * convert ALSA sequencer event to OSS synth event
546 */
547static int
548send_synth_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, int dev)
549{
550 evrec_t ossev;
551
552 memset(&ossev, 0, sizeof(ossev));
553
554 switch (ev->type) {
555 case SNDRV_SEQ_EVENT_NOTEON:
556 ossev.v.cmd = MIDI_NOTEON; break;
557 case SNDRV_SEQ_EVENT_NOTEOFF:
558 ossev.v.cmd = MIDI_NOTEOFF; break;
559 case SNDRV_SEQ_EVENT_KEYPRESS:
560 ossev.v.cmd = MIDI_KEY_PRESSURE; break;
561 case SNDRV_SEQ_EVENT_CONTROLLER:
562 ossev.l.cmd = MIDI_CTL_CHANGE; break;
563 case SNDRV_SEQ_EVENT_PGMCHANGE:
564 ossev.l.cmd = MIDI_PGM_CHANGE; break;
565 case SNDRV_SEQ_EVENT_CHANPRESS:
566 ossev.l.cmd = MIDI_CHN_PRESSURE; break;
567 case SNDRV_SEQ_EVENT_PITCHBEND:
568 ossev.l.cmd = MIDI_PITCH_BEND; break;
569 default:
570 return 0; /* not supported */
571 }
572
573 ossev.v.dev = dev;
574
575 switch (ev->type) {
576 case SNDRV_SEQ_EVENT_NOTEON:
577 case SNDRV_SEQ_EVENT_NOTEOFF:
578 case SNDRV_SEQ_EVENT_KEYPRESS:
579 ossev.v.code = EV_CHN_VOICE;
580 ossev.v.note = ev->data.note.note;
581 ossev.v.parm = ev->data.note.velocity;
582 ossev.v.chn = ev->data.note.channel;
583 break;
584 case SNDRV_SEQ_EVENT_CONTROLLER:
585 case SNDRV_SEQ_EVENT_PGMCHANGE:
586 case SNDRV_SEQ_EVENT_CHANPRESS:
587 ossev.l.code = EV_CHN_COMMON;
588 ossev.l.p1 = ev->data.control.param;
589 ossev.l.val = ev->data.control.value;
590 ossev.l.chn = ev->data.control.channel;
591 break;
592 case SNDRV_SEQ_EVENT_PITCHBEND:
593 ossev.l.code = EV_CHN_COMMON;
594 ossev.l.val = ev->data.control.value + 8192;
595 ossev.l.chn = ev->data.control.channel;
596 break;
597 }
598
599 snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
600 snd_seq_oss_readq_put_event(dp->readq, &ossev);
601
602 return 0;
603}
604
605/*
606 * decode event and send MIDI bytes to read queue
607 */
608static int
609send_midi_event(seq_oss_devinfo_t *dp, snd_seq_event_t *ev, seq_oss_midi_t *mdev)
610{
611 char msg[32];
612 int len;
613
614 snd_seq_oss_readq_put_timestamp(dp->readq, ev->time.tick, dp->seq_mode);
615 if (!dp->timer->running)
616 len = snd_seq_oss_timer_start(dp->timer);
617 if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
618 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
619 snd_seq_oss_readq_puts(dp->readq, mdev->seq_device,
620 ev->data.ext.ptr, ev->data.ext.len);
621 } else {
622 len = snd_midi_event_decode(mdev->coder, msg, sizeof(msg), ev);
623 if (len > 0)
624 snd_seq_oss_readq_puts(dp->readq, mdev->seq_device, msg, len);
625 }
626
627 return 0;
628}
629
630
631/*
632 * dump midi data
633 * return 0 : enqueued
634 * non-zero : invalid - ignored
635 */
636int
637snd_seq_oss_midi_putc(seq_oss_devinfo_t *dp, int dev, unsigned char c, snd_seq_event_t *ev)
638{
639 seq_oss_midi_t *mdev;
640
641 if ((mdev = get_mididev(dp, dev)) == NULL)
642 return -ENODEV;
643 if (snd_midi_event_encode_byte(mdev->coder, c, ev) > 0) {
644 snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
645 snd_use_lock_free(&mdev->use_lock);
646 return 0;
647 }
648 snd_use_lock_free(&mdev->use_lock);
649 return -EINVAL;
650}
651
652/*
653 * create OSS compatible midi_info record
654 */
655int
656snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf)
657{
658 seq_oss_midi_t *mdev;
659
660 if ((mdev = get_mididev(dp, dev)) == NULL)
661 return -ENXIO;
662 inf->device = dev;
663 inf->dev_type = 0; /* FIXME: ?? */
664 inf->capabilities = 0; /* FIXME: ?? */
665 strlcpy(inf->name, mdev->name, sizeof(inf->name));
666 snd_use_lock_free(&mdev->use_lock);
667 return 0;
668}
669
670
671/*
672 * proc interface
673 */
674static char *
675capmode_str(int val)
676{
677 val &= PERM_READ|PERM_WRITE;
678 if (val == (PERM_READ|PERM_WRITE))
679 return "read/write";
680 else if (val == PERM_READ)
681 return "read";
682 else if (val == PERM_WRITE)
683 return "write";
684 else
685 return "none";
686}
687
688void
689snd_seq_oss_midi_info_read(snd_info_buffer_t *buf)
690{
691 int i;
692 seq_oss_midi_t *mdev;
693
694 snd_iprintf(buf, "\nNumber of MIDI devices: %d\n", max_midi_devs);
695 for (i = 0; i < max_midi_devs; i++) {
696 snd_iprintf(buf, "\nmidi %d: ", i);
697 mdev = get_mdev(i);
698 if (mdev == NULL) {
699 snd_iprintf(buf, "*empty*\n");
700 continue;
701 }
702 snd_iprintf(buf, "[%s] ALSA port %d:%d\n", mdev->name,
703 mdev->client, mdev->port);
704 snd_iprintf(buf, " capability %s / opened %s\n",
705 capmode_str(mdev->flags),
706 capmode_str(mdev->opened));
707 snd_use_lock_free(&mdev->use_lock);
708 }
709}
710
diff --git a/sound/core/seq/oss/seq_oss_midi.h b/sound/core/seq/oss/seq_oss_midi.h
new file mode 100644
index 000000000000..462484b2b6fe
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_midi.h
@@ -0,0 +1,49 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * midi device information
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SEQ_OSS_MIDI_H
24#define __SEQ_OSS_MIDI_H
25
26#include "seq_oss_device.h"
27#include <sound/seq_oss_legacy.h>
28
29typedef struct seq_oss_midi_t seq_oss_midi_t;
30
31int snd_seq_oss_midi_lookup_ports(int client);
32int snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo);
33int snd_seq_oss_midi_check_exit_port(int client, int port);
34void snd_seq_oss_midi_clear_all(void);
35
36void snd_seq_oss_midi_setup(seq_oss_devinfo_t *dp);
37void snd_seq_oss_midi_cleanup(seq_oss_devinfo_t *dp);
38
39int snd_seq_oss_midi_open(seq_oss_devinfo_t *dp, int dev, int file_mode);
40void snd_seq_oss_midi_open_all(seq_oss_devinfo_t *dp, int file_mode);
41int snd_seq_oss_midi_close(seq_oss_devinfo_t *dp, int dev);
42void snd_seq_oss_midi_reset(seq_oss_devinfo_t *dp, int dev);
43int snd_seq_oss_midi_putc(seq_oss_devinfo_t *dp, int dev, unsigned char c, snd_seq_event_t *ev);
44int snd_seq_oss_midi_input(snd_seq_event_t *ev, int direct, void *private);
45int snd_seq_oss_midi_filemode(seq_oss_devinfo_t *dp, int dev);
46int snd_seq_oss_midi_make_info(seq_oss_devinfo_t *dp, int dev, struct midi_info *inf);
47void snd_seq_oss_midi_get_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_addr_t *addr);
48
49#endif
diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
new file mode 100644
index 000000000000..0a6f2a64f692
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_readq.c
@@ -0,0 +1,234 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * seq_oss_readq.c - MIDI input queue
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_readq.h"
24#include "seq_oss_event.h"
25#include <sound/seq_oss_legacy.h>
26#include "../seq_lock.h"
27#include <linux/wait.h>
28
29/*
30 * constants
31 */
32//#define SNDRV_SEQ_OSS_MAX_TIMEOUT (unsigned long)(-1)
33#define SNDRV_SEQ_OSS_MAX_TIMEOUT (HZ * 3600)
34
35
36/*
37 * prototypes
38 */
39
40
41/*
42 * create a read queue
43 */
44seq_oss_readq_t *
45snd_seq_oss_readq_new(seq_oss_devinfo_t *dp, int maxlen)
46{
47 seq_oss_readq_t *q;
48
49 if ((q = kcalloc(1, sizeof(*q), GFP_KERNEL)) == NULL) {
50 snd_printk(KERN_ERR "can't malloc read queue\n");
51 return NULL;
52 }
53
54 if ((q->q = kcalloc(maxlen, sizeof(evrec_t), GFP_KERNEL)) == NULL) {
55 snd_printk(KERN_ERR "can't malloc read queue buffer\n");
56 kfree(q);
57 return NULL;
58 }
59
60 q->maxlen = maxlen;
61 q->qlen = 0;
62 q->head = q->tail = 0;
63 init_waitqueue_head(&q->midi_sleep);
64 spin_lock_init(&q->lock);
65 q->pre_event_timeout = SNDRV_SEQ_OSS_MAX_TIMEOUT;
66 q->input_time = (unsigned long)-1;
67
68 return q;
69}
70
71/*
72 * delete the read queue
73 */
74void
75snd_seq_oss_readq_delete(seq_oss_readq_t *q)
76{
77 if (q) {
78 kfree(q->q);
79 kfree(q);
80 }
81}
82
83/*
84 * reset the read queue
85 */
86void
87snd_seq_oss_readq_clear(seq_oss_readq_t *q)
88{
89 if (q->qlen) {
90 q->qlen = 0;
91 q->head = q->tail = 0;
92 }
93 /* if someone sleeping, wake'em up */
94 if (waitqueue_active(&q->midi_sleep))
95 wake_up(&q->midi_sleep);
96 q->input_time = (unsigned long)-1;
97}
98
99/*
100 * put a midi byte
101 */
102int
103snd_seq_oss_readq_puts(seq_oss_readq_t *q, int dev, unsigned char *data, int len)
104{
105 evrec_t rec;
106 int result;
107
108 memset(&rec, 0, sizeof(rec));
109 rec.c[0] = SEQ_MIDIPUTC;
110 rec.c[2] = dev;
111
112 while (len-- > 0) {
113 rec.c[1] = *data++;
114 result = snd_seq_oss_readq_put_event(q, &rec);
115 if (result < 0)
116 return result;
117 }
118 return 0;
119}
120
121/*
122 * copy an event to input queue:
123 * return zero if enqueued
124 */
125int
126snd_seq_oss_readq_put_event(seq_oss_readq_t *q, evrec_t *ev)
127{
128 unsigned long flags;
129
130 spin_lock_irqsave(&q->lock, flags);
131 if (q->qlen >= q->maxlen - 1) {
132 spin_unlock_irqrestore(&q->lock, flags);
133 return -ENOMEM;
134 }
135
136 memcpy(&q->q[q->tail], ev, sizeof(*ev));
137 q->tail = (q->tail + 1) % q->maxlen;
138 q->qlen++;
139
140 /* wake up sleeper */
141 if (waitqueue_active(&q->midi_sleep))
142 wake_up(&q->midi_sleep);
143
144 spin_unlock_irqrestore(&q->lock, flags);
145
146 return 0;
147}
148
149
150/*
151 * pop queue
152 * caller must hold lock
153 */
154int
155snd_seq_oss_readq_pick(seq_oss_readq_t *q, evrec_t *rec)
156{
157 if (q->qlen == 0)
158 return -EAGAIN;
159 memcpy(rec, &q->q[q->head], sizeof(*rec));
160 return 0;
161}
162
163/*
164 * sleep until ready
165 */
166void
167snd_seq_oss_readq_wait(seq_oss_readq_t *q)
168{
169 wait_event_interruptible_timeout(q->midi_sleep,
170 (q->qlen > 0 || q->head == q->tail),
171 q->pre_event_timeout);
172}
173
174/*
175 * drain one record
176 * caller must hold lock
177 */
178void
179snd_seq_oss_readq_free(seq_oss_readq_t *q)
180{
181 if (q->qlen > 0) {
182 q->head = (q->head + 1) % q->maxlen;
183 q->qlen--;
184 }
185}
186
187/*
188 * polling/select:
189 * return non-zero if readq is not empty.
190 */
191unsigned int
192snd_seq_oss_readq_poll(seq_oss_readq_t *q, struct file *file, poll_table *wait)
193{
194 poll_wait(file, &q->midi_sleep, wait);
195 return q->qlen;
196}
197
198/*
199 * put a timestamp
200 */
201int
202snd_seq_oss_readq_put_timestamp(seq_oss_readq_t *q, unsigned long curt, int seq_mode)
203{
204 if (curt != q->input_time) {
205 evrec_t rec;
206 memset(&rec, 0, sizeof(rec));
207 switch (seq_mode) {
208 case SNDRV_SEQ_OSS_MODE_SYNTH:
209 rec.echo = (curt << 8) | SEQ_WAIT;
210 snd_seq_oss_readq_put_event(q, &rec);
211 break;
212 case SNDRV_SEQ_OSS_MODE_MUSIC:
213 rec.t.code = EV_TIMING;
214 rec.t.cmd = TMR_WAIT_ABS;
215 rec.t.time = curt;
216 snd_seq_oss_readq_put_event(q, &rec);
217 break;
218 }
219 q->input_time = curt;
220 }
221 return 0;
222}
223
224
225/*
226 * proc interface
227 */
228void
229snd_seq_oss_readq_info_read(seq_oss_readq_t *q, snd_info_buffer_t *buf)
230{
231 snd_iprintf(buf, " read queue [%s] length = %d : tick = %ld\n",
232 (waitqueue_active(&q->midi_sleep) ? "sleeping":"running"),
233 q->qlen, q->input_time);
234}
diff --git a/sound/core/seq/oss/seq_oss_readq.h b/sound/core/seq/oss/seq_oss_readq.h
new file mode 100644
index 000000000000..303b9298f206
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_readq.h
@@ -0,0 +1,56 @@
1/*
2 * OSS compatible sequencer driver
3 * read fifo queue
4 *
5 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifndef __SEQ_OSS_READQ_H
23#define __SEQ_OSS_READQ_H
24
25#include "seq_oss_device.h"
26
27
28/*
29 * definition of read queue
30 */
31struct seq_oss_readq_t {
32 evrec_t *q;
33 int qlen;
34 int maxlen;
35 int head, tail;
36 unsigned long pre_event_timeout;
37 unsigned long input_time;
38 wait_queue_head_t midi_sleep;
39 spinlock_t lock;
40};
41
42seq_oss_readq_t *snd_seq_oss_readq_new(seq_oss_devinfo_t *dp, int maxlen);
43void snd_seq_oss_readq_delete(seq_oss_readq_t *q);
44void snd_seq_oss_readq_clear(seq_oss_readq_t *readq);
45unsigned int snd_seq_oss_readq_poll(seq_oss_readq_t *readq, struct file *file, poll_table *wait);
46int snd_seq_oss_readq_puts(seq_oss_readq_t *readq, int dev, unsigned char *data, int len);
47int snd_seq_oss_readq_put_event(seq_oss_readq_t *readq, evrec_t *ev);
48int snd_seq_oss_readq_put_timestamp(seq_oss_readq_t *readq, unsigned long curt, int seq_mode);
49int snd_seq_oss_readq_pick(seq_oss_readq_t *q, evrec_t *rec);
50void snd_seq_oss_readq_wait(seq_oss_readq_t *q);
51void snd_seq_oss_readq_free(seq_oss_readq_t *q);
52
53#define snd_seq_oss_readq_lock(q, flags) spin_lock_irqsave(&(q)->lock, flags)
54#define snd_seq_oss_readq_unlock(q, flags) spin_unlock_irqrestore(&(q)->lock, flags)
55
56#endif
diff --git a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
new file mode 100644
index 000000000000..1d8fbd22e3e3
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_rw.c
@@ -0,0 +1,216 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * read/write/select interface to device file
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_device.h"
24#include "seq_oss_readq.h"
25#include "seq_oss_writeq.h"
26#include "seq_oss_synth.h"
27#include <sound/seq_oss_legacy.h>
28#include "seq_oss_event.h"
29#include "seq_oss_timer.h"
30#include "../seq_clientmgr.h"
31
32
33/*
34 * protoypes
35 */
36static int insert_queue(seq_oss_devinfo_t *dp, evrec_t *rec, struct file *opt);
37
38
39/*
40 * read interface
41 */
42
43int
44snd_seq_oss_read(seq_oss_devinfo_t *dp, char __user *buf, int count)
45{
46 seq_oss_readq_t *readq = dp->readq;
47 int result = 0, err = 0;
48 int ev_len;
49 evrec_t rec;
50 unsigned long flags;
51
52 if (readq == NULL || ! is_read_mode(dp->file_mode))
53 return -ENXIO;
54
55 while (count >= SHORT_EVENT_SIZE) {
56 snd_seq_oss_readq_lock(readq, flags);
57 err = snd_seq_oss_readq_pick(readq, &rec);
58 if (err == -EAGAIN &&
59 !is_nonblock_mode(dp->file_mode) && result == 0) {
60 snd_seq_oss_readq_unlock(readq, flags);
61 snd_seq_oss_readq_wait(readq);
62 snd_seq_oss_readq_lock(readq, flags);
63 if (signal_pending(current))
64 err = -ERESTARTSYS;
65 else
66 err = snd_seq_oss_readq_pick(readq, &rec);
67 }
68 if (err < 0) {
69 snd_seq_oss_readq_unlock(readq, flags);
70 break;
71 }
72 ev_len = ev_length(&rec);
73 if (ev_len < count) {
74 snd_seq_oss_readq_unlock(readq, flags);
75 break;
76 }
77 snd_seq_oss_readq_free(readq);
78 snd_seq_oss_readq_unlock(readq, flags);
79 if (copy_to_user(buf, &rec, ev_len)) {
80 err = -EFAULT;
81 break;
82 }
83 result += ev_len;
84 buf += ev_len;
85 count -= ev_len;
86 }
87 return result > 0 ? result : err;
88}
89
90
91/*
92 * write interface
93 */
94
95int
96snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt)
97{
98 int result = 0, err = 0;
99 int ev_size, fmt;
100 evrec_t rec;
101
102 if (! is_write_mode(dp->file_mode) || dp->writeq == NULL)
103 return -ENXIO;
104
105 while (count >= SHORT_EVENT_SIZE) {
106 if (copy_from_user(&rec, buf, SHORT_EVENT_SIZE)) {
107 err = -EFAULT;
108 break;
109 }
110 if (rec.s.code == SEQ_FULLSIZE) {
111 /* load patch */
112 if (result > 0) {
113 err = -EINVAL;
114 break;
115 }
116 fmt = (*(unsigned short *)rec.c) & 0xffff;
117 /* FIXME the return value isn't correct */
118 return snd_seq_oss_synth_load_patch(dp, rec.s.dev,
119 fmt, buf, 0, count);
120 }
121 if (ev_is_long(&rec)) {
122 /* extended code */
123 if (rec.s.code == SEQ_EXTENDED &&
124 dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
125 err = -EINVAL;
126 break;
127 }
128 ev_size = LONG_EVENT_SIZE;
129 if (count < ev_size)
130 break;
131 /* copy the reset 4 bytes */
132 if (copy_from_user(rec.c + SHORT_EVENT_SIZE,
133 buf + SHORT_EVENT_SIZE,
134 LONG_EVENT_SIZE - SHORT_EVENT_SIZE)) {
135 err = -EFAULT;
136 break;
137 }
138 } else {
139 /* old-type code */
140 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_MUSIC) {
141 err = -EINVAL;
142 break;
143 }
144 ev_size = SHORT_EVENT_SIZE;
145 }
146
147 /* insert queue */
148 if ((err = insert_queue(dp, &rec, opt)) < 0)
149 break;
150
151 result += ev_size;
152 buf += ev_size;
153 count -= ev_size;
154 }
155 return result > 0 ? result : err;
156}
157
158
159/*
160 * insert event record to write queue
161 * return: 0 = OK, non-zero = NG
162 */
163static int
164insert_queue(seq_oss_devinfo_t *dp, evrec_t *rec, struct file *opt)
165{
166 int rc = 0;
167 snd_seq_event_t event;
168
169 /* if this is a timing event, process the current time */
170 if (snd_seq_oss_process_timer_event(dp->timer, rec))
171 return 0; /* no need to insert queue */
172
173 /* parse this event */
174 memset(&event, 0, sizeof(event));
175 /* set dummy -- to be sure */
176 event.type = SNDRV_SEQ_EVENT_NOTEOFF;
177 snd_seq_oss_fill_addr(dp, &event, dp->addr.port, dp->addr.client);
178
179 if (snd_seq_oss_process_event(dp, rec, &event))
180 return 0; /* invalid event - no need to insert queue */
181
182 event.time.tick = snd_seq_oss_timer_cur_tick(dp->timer);
183 if (dp->timer->realtime || !dp->timer->running) {
184 snd_seq_oss_dispatch(dp, &event, 0, 0);
185 } else {
186 if (is_nonblock_mode(dp->file_mode))
187 rc = snd_seq_kernel_client_enqueue(dp->cseq, &event, 0, 0);
188 else
189 rc = snd_seq_kernel_client_enqueue_blocking(dp->cseq, &event, opt, 0, 0);
190 }
191 return rc;
192}
193
194
195/*
196 * select / poll
197 */
198
199unsigned int
200snd_seq_oss_poll(seq_oss_devinfo_t *dp, struct file *file, poll_table * wait)
201{
202 unsigned int mask = 0;
203
204 /* input */
205 if (dp->readq && is_read_mode(dp->file_mode)) {
206 if (snd_seq_oss_readq_poll(dp->readq, file, wait))
207 mask |= POLLIN | POLLRDNORM;
208 }
209
210 /* output */
211 if (dp->writeq && is_write_mode(dp->file_mode)) {
212 if (snd_seq_kernel_client_write_poll(dp->cseq, file, wait))
213 mask |= POLLOUT | POLLWRNORM;
214 }
215 return mask;
216}
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
new file mode 100644
index 000000000000..638cc148706d
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_synth.c
@@ -0,0 +1,659 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * synth device handlers
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_synth.h"
24#include "seq_oss_midi.h"
25#include "../seq_lock.h"
26#include <linux/init.h>
27
28/*
29 * constants
30 */
31#define SNDRV_SEQ_OSS_MAX_SYNTH_NAME 30
32#define MAX_SYSEX_BUFLEN 128
33
34
35/*
36 * definition of synth info records
37 */
38
39/* sysex buffer */
40struct seq_oss_synth_sysex_t {
41 int len;
42 int skip;
43 unsigned char buf[MAX_SYSEX_BUFLEN];
44};
45
46/* synth info */
47struct seq_oss_synth_t {
48 int seq_device;
49
50 /* for synth_info */
51 int synth_type;
52 int synth_subtype;
53 int nr_voices;
54
55 char name[SNDRV_SEQ_OSS_MAX_SYNTH_NAME];
56 snd_seq_oss_callback_t oper;
57
58 int opened;
59
60 void *private_data;
61 snd_use_lock_t use_lock;
62};
63
64
65/*
66 * device table
67 */
68static int max_synth_devs;
69static seq_oss_synth_t *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS];
70static seq_oss_synth_t midi_synth_dev = {
71 -1, /* seq_device */
72 SYNTH_TYPE_MIDI, /* synth_type */
73 0, /* synth_subtype */
74 16, /* nr_voices */
75 "MIDI", /* name */
76};
77
78static DEFINE_SPINLOCK(register_lock);
79
80/*
81 * prototypes
82 */
83static seq_oss_synth_t *get_synthdev(seq_oss_devinfo_t *dp, int dev);
84static void reset_channels(seq_oss_synthinfo_t *info);
85
86/*
87 * global initialization
88 */
89void __init
90snd_seq_oss_synth_init(void)
91{
92 snd_use_lock_init(&midi_synth_dev.use_lock);
93}
94
95/*
96 * registration of the synth device
97 */
98int
99snd_seq_oss_synth_register(snd_seq_device_t *dev)
100{
101 int i;
102 seq_oss_synth_t *rec;
103 snd_seq_oss_reg_t *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
104 unsigned long flags;
105
106 if ((rec = kcalloc(1, sizeof(*rec), GFP_KERNEL)) == NULL) {
107 snd_printk(KERN_ERR "can't malloc synth info\n");
108 return -ENOMEM;
109 }
110 rec->seq_device = -1;
111 rec->synth_type = reg->type;
112 rec->synth_subtype = reg->subtype;
113 rec->nr_voices = reg->nvoices;
114 rec->oper = reg->oper;
115 rec->private_data = reg->private_data;
116 rec->opened = 0;
117 snd_use_lock_init(&rec->use_lock);
118
119 /* copy and truncate the name of synth device */
120 strlcpy(rec->name, dev->name, sizeof(rec->name));
121
122 /* registration */
123 spin_lock_irqsave(&register_lock, flags);
124 for (i = 0; i < max_synth_devs; i++) {
125 if (synth_devs[i] == NULL)
126 break;
127 }
128 if (i >= max_synth_devs) {
129 if (max_synth_devs >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS) {
130 spin_unlock_irqrestore(&register_lock, flags);
131 snd_printk(KERN_ERR "no more synth slot\n");
132 kfree(rec);
133 return -ENOMEM;
134 }
135 max_synth_devs++;
136 }
137 rec->seq_device = i;
138 synth_devs[i] = rec;
139 debug_printk(("synth %s registered %d\n", rec->name, i));
140 spin_unlock_irqrestore(&register_lock, flags);
141 dev->driver_data = rec;
142#ifdef SNDRV_OSS_INFO_DEV_SYNTH
143 if (i < SNDRV_CARDS)
144 snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, i, rec->name);
145#endif
146 return 0;
147}
148
149
150int
151snd_seq_oss_synth_unregister(snd_seq_device_t *dev)
152{
153 int index;
154 seq_oss_synth_t *rec = dev->driver_data;
155 unsigned long flags;
156
157 spin_lock_irqsave(&register_lock, flags);
158 for (index = 0; index < max_synth_devs; index++) {
159 if (synth_devs[index] == rec)
160 break;
161 }
162 if (index >= max_synth_devs) {
163 spin_unlock_irqrestore(&register_lock, flags);
164 snd_printk(KERN_ERR "can't unregister synth\n");
165 return -EINVAL;
166 }
167 synth_devs[index] = NULL;
168 if (index == max_synth_devs - 1) {
169 for (index--; index >= 0; index--) {
170 if (synth_devs[index])
171 break;
172 }
173 max_synth_devs = index + 1;
174 }
175 spin_unlock_irqrestore(&register_lock, flags);
176#ifdef SNDRV_OSS_INFO_DEV_SYNTH
177 if (rec->seq_device < SNDRV_CARDS)
178 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device);
179#endif
180
181 snd_use_lock_sync(&rec->use_lock);
182 kfree(rec);
183
184 return 0;
185}
186
187
188/*
189 */
190static seq_oss_synth_t *
191get_sdev(int dev)
192{
193 seq_oss_synth_t *rec;
194 unsigned long flags;
195
196 spin_lock_irqsave(&register_lock, flags);
197 rec = synth_devs[dev];
198 if (rec)
199 snd_use_lock_use(&rec->use_lock);
200 spin_unlock_irqrestore(&register_lock, flags);
201 return rec;
202}
203
204
205/*
206 * set up synth tables
207 */
208
209void
210snd_seq_oss_synth_setup(seq_oss_devinfo_t *dp)
211{
212 int i;
213 seq_oss_synth_t *rec;
214 seq_oss_synthinfo_t *info;
215
216 dp->max_synthdev = max_synth_devs;
217 dp->synth_opened = 0;
218 memset(dp->synths, 0, sizeof(dp->synths));
219 for (i = 0; i < dp->max_synthdev; i++) {
220 rec = get_sdev(i);
221 if (rec == NULL)
222 continue;
223 if (rec->oper.open == NULL || rec->oper.close == NULL) {
224 snd_use_lock_free(&rec->use_lock);
225 continue;
226 }
227 info = &dp->synths[i];
228 info->arg.app_index = dp->port;
229 info->arg.file_mode = dp->file_mode;
230 info->arg.seq_mode = dp->seq_mode;
231 if (dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
232 info->arg.event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
233 else
234 info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS;
235 info->opened = 0;
236 if (!try_module_get(rec->oper.owner)) {
237 snd_use_lock_free(&rec->use_lock);
238 continue;
239 }
240 if (rec->oper.open(&info->arg, rec->private_data) < 0) {
241 module_put(rec->oper.owner);
242 snd_use_lock_free(&rec->use_lock);
243 continue;
244 }
245 info->nr_voices = rec->nr_voices;
246 if (info->nr_voices > 0) {
247 info->ch = kcalloc(info->nr_voices, sizeof(seq_oss_chinfo_t), GFP_KERNEL);
248 if (!info->ch)
249 BUG();
250 reset_channels(info);
251 }
252 debug_printk(("synth %d assigned\n", i));
253 info->opened++;
254 rec->opened++;
255 dp->synth_opened++;
256 snd_use_lock_free(&rec->use_lock);
257 }
258}
259
260
261/*
262 * set up synth tables for MIDI emulation - /dev/music mode only
263 */
264
265void
266snd_seq_oss_synth_setup_midi(seq_oss_devinfo_t *dp)
267{
268 int i;
269
270 if (dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)
271 return;
272
273 for (i = 0; i < dp->max_mididev; i++) {
274 seq_oss_synthinfo_t *info;
275 info = &dp->synths[dp->max_synthdev];
276 if (snd_seq_oss_midi_open(dp, i, dp->file_mode) < 0)
277 continue;
278 info->arg.app_index = dp->port;
279 info->arg.file_mode = dp->file_mode;
280 info->arg.seq_mode = dp->seq_mode;
281 info->arg.private_data = info;
282 info->is_midi = 1;
283 info->midi_mapped = i;
284 info->arg.event_passing = SNDRV_SEQ_OSS_PASS_EVENTS;
285 snd_seq_oss_midi_get_addr(dp, i, &info->arg.addr);
286 info->opened = 1;
287 midi_synth_dev.opened++;
288 dp->max_synthdev++;
289 if (dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS)
290 break;
291 }
292}
293
294
295/*
296 * clean up synth tables
297 */
298
299void
300snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp)
301{
302 int i;
303 seq_oss_synth_t *rec;
304 seq_oss_synthinfo_t *info;
305
306 snd_assert(dp->max_synthdev <= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS, return);
307 for (i = 0; i < dp->max_synthdev; i++) {
308 info = &dp->synths[i];
309 if (! info->opened)
310 continue;
311 if (info->is_midi) {
312 if (midi_synth_dev.opened > 0) {
313 snd_seq_oss_midi_close(dp, info->midi_mapped);
314 midi_synth_dev.opened--;
315 }
316 } else {
317 rec = get_sdev(i);
318 if (rec == NULL)
319 continue;
320 if (rec->opened > 0) {
321 debug_printk(("synth %d closed\n", i));
322 rec->oper.close(&info->arg);
323 module_put(rec->oper.owner);
324 rec->opened = 0;
325 }
326 snd_use_lock_free(&rec->use_lock);
327 }
328 if (info->sysex) {
329 kfree(info->sysex);
330 info->sysex = NULL;
331 }
332 if (info->ch) {
333 kfree(info->ch);
334 info->ch = NULL;
335 }
336 }
337 dp->synth_opened = 0;
338 dp->max_synthdev = 0;
339}
340
341/*
342 * check if the specified device is MIDI mapped device
343 */
344static int
345is_midi_dev(seq_oss_devinfo_t *dp, int dev)
346{
347 if (dev < 0 || dev >= dp->max_synthdev)
348 return 0;
349 if (dp->synths[dev].is_midi)
350 return 1;
351 return 0;
352}
353
354/*
355 * return synth device information pointer
356 */
357static seq_oss_synth_t *
358get_synthdev(seq_oss_devinfo_t *dp, int dev)
359{
360 seq_oss_synth_t *rec;
361 if (dev < 0 || dev >= dp->max_synthdev)
362 return NULL;
363 if (! dp->synths[dev].opened)
364 return NULL;
365 if (dp->synths[dev].is_midi)
366 return &midi_synth_dev;
367 if ((rec = get_sdev(dev)) == NULL)
368 return NULL;
369 if (! rec->opened) {
370 snd_use_lock_free(&rec->use_lock);
371 return NULL;
372 }
373 return rec;
374}
375
376
377/*
378 * reset note and velocity on each channel.
379 */
380static void
381reset_channels(seq_oss_synthinfo_t *info)
382{
383 int i;
384 if (info->ch == NULL || ! info->nr_voices)
385 return;
386 for (i = 0; i < info->nr_voices; i++) {
387 info->ch[i].note = -1;
388 info->ch[i].vel = 0;
389 }
390}
391
392
393/*
394 * reset synth device:
395 * call reset callback. if no callback is defined, send a heartbeat
396 * event to the corresponding port.
397 */
398void
399snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev)
400{
401 seq_oss_synth_t *rec;
402 seq_oss_synthinfo_t *info;
403
404 snd_assert(dev >= 0 && dev < dp->max_synthdev, return);
405 info = &dp->synths[dev];
406 if (! info->opened)
407 return;
408 if (info->sysex)
409 info->sysex->len = 0; /* reset sysex */
410 reset_channels(info);
411 if (info->is_midi) {
412 if (midi_synth_dev.opened <= 0)
413 return;
414 snd_seq_oss_midi_reset(dp, info->midi_mapped);
415 /* reopen the device */
416 snd_seq_oss_midi_close(dp, dev);
417 if (snd_seq_oss_midi_open(dp, info->midi_mapped,
418 dp->file_mode) < 0) {
419 midi_synth_dev.opened--;
420 info->opened = 0;
421 if (info->sysex) {
422 kfree(info->sysex);
423 info->sysex = NULL;
424 }
425 if (info->ch) {
426 kfree(info->ch);
427 info->ch = NULL;
428 }
429 }
430 return;
431 }
432
433 rec = get_sdev(dev);
434 if (rec == NULL)
435 return;
436 if (rec->oper.reset) {
437 rec->oper.reset(&info->arg);
438 } else {
439 snd_seq_event_t ev;
440 memset(&ev, 0, sizeof(ev));
441 snd_seq_oss_fill_addr(dp, &ev, info->arg.addr.client,
442 info->arg.addr.port);
443 ev.type = SNDRV_SEQ_EVENT_RESET;
444 snd_seq_oss_dispatch(dp, &ev, 0, 0);
445 }
446 snd_use_lock_free(&rec->use_lock);
447}
448
449
450/*
451 * load a patch record:
452 * call load_patch callback function
453 */
454int
455snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt,
456 const char __user *buf, int p, int c)
457{
458 seq_oss_synth_t *rec;
459 int rc;
460
461 if (dev < 0 || dev >= dp->max_synthdev)
462 return -ENXIO;
463
464 if (is_midi_dev(dp, dev))
465 return 0;
466 if ((rec = get_synthdev(dp, dev)) == NULL)
467 return -ENXIO;
468
469 if (rec->oper.load_patch == NULL)
470 rc = -ENXIO;
471 else
472 rc = rec->oper.load_patch(&dp->synths[dev].arg, fmt, buf, p, c);
473 snd_use_lock_free(&rec->use_lock);
474 return rc;
475}
476
477/*
478 * check if the device is valid synth device
479 */
480int
481snd_seq_oss_synth_is_valid(seq_oss_devinfo_t *dp, int dev)
482{
483 seq_oss_synth_t *rec;
484 rec = get_synthdev(dp, dev);
485 if (rec) {
486 snd_use_lock_free(&rec->use_lock);
487 return 1;
488 }
489 return 0;
490}
491
492
493/*
494 * receive OSS 6 byte sysex packet:
495 * the full sysex message will be sent if it reaches to the end of data
496 * (0xff).
497 */
498int
499snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_seq_event_t *ev)
500{
501 int i, send;
502 unsigned char *dest;
503 seq_oss_synth_sysex_t *sysex;
504
505 if (! snd_seq_oss_synth_is_valid(dp, dev))
506 return -ENXIO;
507
508 sysex = dp->synths[dev].sysex;
509 if (sysex == NULL) {
510 sysex = kcalloc(1, sizeof(*sysex), GFP_KERNEL);
511 if (sysex == NULL)
512 return -ENOMEM;
513 dp->synths[dev].sysex = sysex;
514 }
515
516 send = 0;
517 dest = sysex->buf + sysex->len;
518 /* copy 6 byte packet to the buffer */
519 for (i = 0; i < 6; i++) {
520 if (buf[i] == 0xff) {
521 send = 1;
522 break;
523 }
524 dest[i] = buf[i];
525 sysex->len++;
526 if (sysex->len >= MAX_SYSEX_BUFLEN) {
527 sysex->len = 0;
528 sysex->skip = 1;
529 break;
530 }
531 }
532
533 if (sysex->len && send) {
534 if (sysex->skip) {
535 sysex->skip = 0;
536 sysex->len = 0;
537 return -EINVAL; /* skip */
538 }
539 /* copy the data to event record and send it */
540 ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
541 if (snd_seq_oss_synth_addr(dp, dev, ev))
542 return -EINVAL;
543 ev->data.ext.len = sysex->len;
544 ev->data.ext.ptr = sysex->buf;
545 sysex->len = 0;
546 return 0;
547 }
548
549 return -EINVAL; /* skip */
550}
551
552/*
553 * fill the event source/destination addresses
554 */
555int
556snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev)
557{
558 if (! snd_seq_oss_synth_is_valid(dp, dev))
559 return -EINVAL;
560 snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client,
561 dp->synths[dev].arg.addr.port);
562 return 0;
563}
564
565
566/*
567 * OSS compatible ioctl
568 */
569int
570snd_seq_oss_synth_ioctl(seq_oss_devinfo_t *dp, int dev, unsigned int cmd, unsigned long addr)
571{
572 seq_oss_synth_t *rec;
573 int rc;
574
575 if (is_midi_dev(dp, dev))
576 return -ENXIO;
577 if ((rec = get_synthdev(dp, dev)) == NULL)
578 return -ENXIO;
579 if (rec->oper.ioctl == NULL)
580 rc = -ENXIO;
581 else
582 rc = rec->oper.ioctl(&dp->synths[dev].arg, cmd, addr);
583 snd_use_lock_free(&rec->use_lock);
584 return rc;
585}
586
587
588/*
589 * send OSS raw events - SEQ_PRIVATE and SEQ_VOLUME
590 */
591int
592snd_seq_oss_synth_raw_event(seq_oss_devinfo_t *dp, int dev, unsigned char *data, snd_seq_event_t *ev)
593{
594 if (! snd_seq_oss_synth_is_valid(dp, dev) || is_midi_dev(dp, dev))
595 return -ENXIO;
596 ev->type = SNDRV_SEQ_EVENT_OSS;
597 memcpy(ev->data.raw8.d, data, 8);
598 return snd_seq_oss_synth_addr(dp, dev, ev);
599}
600
601
602/*
603 * create OSS compatible synth_info record
604 */
605int
606snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *inf)
607{
608 seq_oss_synth_t *rec;
609
610 if (dp->synths[dev].is_midi) {
611 struct midi_info minf;
612 snd_seq_oss_midi_make_info(dp, dp->synths[dev].midi_mapped, &minf);
613 inf->synth_type = SYNTH_TYPE_MIDI;
614 inf->synth_subtype = 0;
615 inf->nr_voices = 16;
616 inf->device = dev;
617 strlcpy(inf->name, minf.name, sizeof(inf->name));
618 } else {
619 if ((rec = get_synthdev(dp, dev)) == NULL)
620 return -ENXIO;
621 inf->synth_type = rec->synth_type;
622 inf->synth_subtype = rec->synth_subtype;
623 inf->nr_voices = rec->nr_voices;
624 inf->device = dev;
625 strlcpy(inf->name, rec->name, sizeof(inf->name));
626 snd_use_lock_free(&rec->use_lock);
627 }
628 return 0;
629}
630
631
632/*
633 * proc interface
634 */
635void
636snd_seq_oss_synth_info_read(snd_info_buffer_t *buf)
637{
638 int i;
639 seq_oss_synth_t *rec;
640
641 snd_iprintf(buf, "\nNumber of synth devices: %d\n", max_synth_devs);
642 for (i = 0; i < max_synth_devs; i++) {
643 snd_iprintf(buf, "\nsynth %d: ", i);
644 rec = get_sdev(i);
645 if (rec == NULL) {
646 snd_iprintf(buf, "*empty*\n");
647 continue;
648 }
649 snd_iprintf(buf, "[%s]\n", rec->name);
650 snd_iprintf(buf, " type 0x%x : subtype 0x%x : voices %d\n",
651 rec->synth_type, rec->synth_subtype,
652 rec->nr_voices);
653 snd_iprintf(buf, " capabilities : ioctl %s / load_patch %s\n",
654 enabled_str((long)rec->oper.ioctl),
655 enabled_str((long)rec->oper.load_patch));
656 snd_use_lock_free(&rec->use_lock);
657 }
658}
659
diff --git a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h
new file mode 100644
index 000000000000..07bc0e2cfb82
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_synth.h
@@ -0,0 +1,49 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * synth device information
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#ifndef __SEQ_OSS_SYNTH_H
24#define __SEQ_OSS_SYNTH_H
25
26#include "seq_oss_device.h"
27#include <sound/seq_oss_legacy.h>
28#include <sound/seq_device.h>
29
30typedef struct seq_oss_synth_t seq_oss_synth_t;
31
32void snd_seq_oss_synth_init(void);
33int snd_seq_oss_synth_register(snd_seq_device_t *dev);
34int snd_seq_oss_synth_unregister(snd_seq_device_t *dev);
35void snd_seq_oss_synth_setup(seq_oss_devinfo_t *dp);
36void snd_seq_oss_synth_setup_midi(seq_oss_devinfo_t *dp);
37void snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp);
38
39void snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev);
40int snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt, const char __user *buf, int p, int c);
41int snd_seq_oss_synth_is_valid(seq_oss_devinfo_t *dp, int dev);
42int snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_seq_event_t *ev);
43int snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev);
44int snd_seq_oss_synth_ioctl(seq_oss_devinfo_t *dp, int dev, unsigned int cmd, unsigned long addr);
45int snd_seq_oss_synth_raw_event(seq_oss_devinfo_t *dp, int dev, unsigned char *data, snd_seq_event_t *ev);
46
47int snd_seq_oss_synth_make_info(seq_oss_devinfo_t *dp, int dev, struct synth_info *inf);
48
49#endif
diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
new file mode 100644
index 000000000000..42ca9493fa60
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_timer.c
@@ -0,0 +1,283 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * Timer control routines
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_timer.h"
24#include "seq_oss_event.h"
25#include <sound/seq_oss_legacy.h>
26
27/*
28 */
29#define MIN_OSS_TEMPO 8
30#define MAX_OSS_TEMPO 360
31#define MIN_OSS_TIMEBASE 1
32#define MAX_OSS_TIMEBASE 1000
33
34/*
35 */
36static void calc_alsa_tempo(seq_oss_timer_t *timer);
37static int send_timer_event(seq_oss_devinfo_t *dp, int type, int value);
38
39
40/*
41 * create and register a new timer.
42 * if queue is not started yet, start it.
43 */
44seq_oss_timer_t *
45snd_seq_oss_timer_new(seq_oss_devinfo_t *dp)
46{
47 seq_oss_timer_t *rec;
48
49 rec = kcalloc(1, sizeof(*rec), GFP_KERNEL);
50 if (rec == NULL)
51 return NULL;
52
53 rec->dp = dp;
54 rec->cur_tick = 0;
55 rec->realtime = 0;
56 rec->running = 0;
57 rec->oss_tempo = 60;
58 rec->oss_timebase = 100;
59 calc_alsa_tempo(rec);
60
61 return rec;
62}
63
64
65/*
66 * delete timer.
67 * if no more timer exists, stop the queue.
68 */
69void
70snd_seq_oss_timer_delete(seq_oss_timer_t *rec)
71{
72 if (rec) {
73 snd_seq_oss_timer_stop(rec);
74 kfree(rec);
75 }
76}
77
78
79/*
80 * process one timing event
81 * return 1 : event proceseed -- skip this event
82 * 0 : not a timer event -- enqueue this event
83 */
84int
85snd_seq_oss_process_timer_event(seq_oss_timer_t *rec, evrec_t *ev)
86{
87 abstime_t parm = ev->t.time;
88
89 if (ev->t.code == EV_TIMING) {
90 switch (ev->t.cmd) {
91 case TMR_WAIT_REL:
92 parm += rec->cur_tick;
93 rec->realtime = 0;
94 /* continue to next */
95 case TMR_WAIT_ABS:
96 if (parm == 0) {
97 rec->realtime = 1;
98 } else if (parm >= rec->cur_tick) {
99 rec->realtime = 0;
100 rec->cur_tick = parm;
101 }
102 return 1; /* skip this event */
103
104 case TMR_START:
105 snd_seq_oss_timer_start(rec);
106 return 1;
107
108 }
109 } else if (ev->s.code == SEQ_WAIT) {
110 /* time = from 1 to 3 bytes */
111 parm = (ev->echo >> 8) & 0xffffff;
112 if (parm > rec->cur_tick) {
113 /* set next event time */
114 rec->cur_tick = parm;
115 rec->realtime = 0;
116 }
117 return 1;
118 }
119
120 return 0;
121}
122
123
124/*
125 * convert tempo units
126 */
127static void
128calc_alsa_tempo(seq_oss_timer_t *timer)
129{
130 timer->tempo = (60 * 1000000) / timer->oss_tempo;
131 timer->ppq = timer->oss_timebase;
132}
133
134
135/*
136 * dispatch a timer event
137 */
138static int
139send_timer_event(seq_oss_devinfo_t *dp, int type, int value)
140{
141 snd_seq_event_t ev;
142
143 memset(&ev, 0, sizeof(ev));
144 ev.type = type;
145 ev.source.client = dp->cseq;
146 ev.source.port = 0;
147 ev.dest.client = SNDRV_SEQ_CLIENT_SYSTEM;
148 ev.dest.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
149 ev.queue = dp->queue;
150 ev.data.queue.queue = dp->queue;
151 ev.data.queue.param.value = value;
152 return snd_seq_kernel_client_dispatch(dp->cseq, &ev, 1, 0);
153}
154
155/*
156 * set queue tempo and start queue
157 */
158int
159snd_seq_oss_timer_start(seq_oss_timer_t *timer)
160{
161 seq_oss_devinfo_t *dp = timer->dp;
162 snd_seq_queue_tempo_t tmprec;
163
164 if (timer->running)
165 snd_seq_oss_timer_stop(timer);
166
167 memset(&tmprec, 0, sizeof(tmprec));
168 tmprec.queue = dp->queue;
169 tmprec.ppq = timer->ppq;
170 tmprec.tempo = timer->tempo;
171 snd_seq_set_queue_tempo(dp->cseq, &tmprec);
172
173 send_timer_event(dp, SNDRV_SEQ_EVENT_START, 0);
174 timer->running = 1;
175 timer->cur_tick = 0;
176 return 0;
177}
178
179
180/*
181 * stop queue
182 */
183int
184snd_seq_oss_timer_stop(seq_oss_timer_t *timer)
185{
186 if (! timer->running)
187 return 0;
188 send_timer_event(timer->dp, SNDRV_SEQ_EVENT_STOP, 0);
189 timer->running = 0;
190 return 0;
191}
192
193
194/*
195 * continue queue
196 */
197int
198snd_seq_oss_timer_continue(seq_oss_timer_t *timer)
199{
200 if (timer->running)
201 return 0;
202 send_timer_event(timer->dp, SNDRV_SEQ_EVENT_CONTINUE, 0);
203 timer->running = 1;
204 return 0;
205}
206
207
208/*
209 * change queue tempo
210 */
211int
212snd_seq_oss_timer_tempo(seq_oss_timer_t *timer, int value)
213{
214 if (value < MIN_OSS_TEMPO)
215 value = MIN_OSS_TEMPO;
216 else if (value > MAX_OSS_TEMPO)
217 value = MAX_OSS_TEMPO;
218 timer->oss_tempo = value;
219 calc_alsa_tempo(timer);
220 if (timer->running)
221 send_timer_event(timer->dp, SNDRV_SEQ_EVENT_TEMPO, timer->tempo);
222 return 0;
223}
224
225
226/*
227 * ioctls
228 */
229int
230snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *arg)
231{
232 int value;
233
234 if (cmd == SNDCTL_SEQ_CTRLRATE) {
235 debug_printk(("ctrl rate\n"));
236 /* if *arg == 0, just return the current rate */
237 if (get_user(value, arg))
238 return -EFAULT;
239 if (value)
240 return -EINVAL;
241 value = ((timer->oss_tempo * timer->oss_timebase) + 30) / 60;
242 return put_user(value, arg) ? -EFAULT : 0;
243 }
244
245 if (timer->dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
246 return 0;
247
248 switch (cmd) {
249 case SNDCTL_TMR_START:
250 debug_printk(("timer start\n"));
251 return snd_seq_oss_timer_start(timer);
252 case SNDCTL_TMR_STOP:
253 debug_printk(("timer stop\n"));
254 return snd_seq_oss_timer_stop(timer);
255 case SNDCTL_TMR_CONTINUE:
256 debug_printk(("timer continue\n"));
257 return snd_seq_oss_timer_continue(timer);
258 case SNDCTL_TMR_TEMPO:
259 debug_printk(("timer tempo\n"));
260 if (get_user(value, arg))
261 return -EFAULT;
262 return snd_seq_oss_timer_tempo(timer, value);
263 case SNDCTL_TMR_TIMEBASE:
264 debug_printk(("timer timebase\n"));
265 if (get_user(value, arg))
266 return -EFAULT;
267 if (value < MIN_OSS_TIMEBASE)
268 value = MIN_OSS_TIMEBASE;
269 else if (value > MAX_OSS_TIMEBASE)
270 value = MAX_OSS_TIMEBASE;
271 timer->oss_timebase = value;
272 calc_alsa_tempo(timer);
273 return 0;
274
275 case SNDCTL_TMR_METRONOME:
276 case SNDCTL_TMR_SELECT:
277 case SNDCTL_TMR_SOURCE:
278 debug_printk(("timer XXX\n"));
279 /* not supported */
280 return 0;
281 }
282 return 0;
283}
diff --git a/sound/core/seq/oss/seq_oss_timer.h b/sound/core/seq/oss/seq_oss_timer.h
new file mode 100644
index 000000000000..6e4dbd8504c1
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_timer.h
@@ -0,0 +1,70 @@
1/*
2 * OSS compatible sequencer driver
3 * timer handling routines
4 *
5 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifndef __SEQ_OSS_TIMER_H
23#define __SEQ_OSS_TIMER_H
24
25#include "seq_oss_device.h"
26
27/*
28 * timer information definition
29 */
30struct seq_oss_timer_t {
31 seq_oss_devinfo_t *dp;
32 reltime_t cur_tick;
33 int realtime;
34 int running;
35 int tempo, ppq; /* ALSA queue */
36 int oss_tempo, oss_timebase;
37};
38
39
40seq_oss_timer_t *snd_seq_oss_timer_new(seq_oss_devinfo_t *dp);
41void snd_seq_oss_timer_delete(seq_oss_timer_t *dp);
42
43int snd_seq_oss_timer_start(seq_oss_timer_t *timer);
44int snd_seq_oss_timer_stop(seq_oss_timer_t *timer);
45int snd_seq_oss_timer_continue(seq_oss_timer_t *timer);
46int snd_seq_oss_timer_tempo(seq_oss_timer_t *timer, int value);
47#define snd_seq_oss_timer_reset snd_seq_oss_timer_start
48
49int snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *arg);
50
51/*
52 * get current processed time
53 */
54static inline abstime_t
55snd_seq_oss_timer_cur_tick(seq_oss_timer_t *timer)
56{
57 return timer->cur_tick;
58}
59
60
61/*
62 * is realtime event?
63 */
64static inline int
65snd_seq_oss_timer_is_realtime(seq_oss_timer_t *timer)
66{
67 return timer->realtime;
68}
69
70#endif
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
new file mode 100644
index 000000000000..87f85f7ee814
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_writeq.c
@@ -0,0 +1,170 @@
1/*
2 * OSS compatible sequencer driver
3 *
4 * seq_oss_writeq.c - write queue and sync
5 *
6 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include "seq_oss_writeq.h"
24#include "seq_oss_event.h"
25#include "seq_oss_timer.h"
26#include <sound/seq_oss_legacy.h>
27#include "../seq_lock.h"
28#include "../seq_clientmgr.h"
29#include <linux/wait.h>
30
31
32/*
33 * create a write queue record
34 */
35seq_oss_writeq_t *
36snd_seq_oss_writeq_new(seq_oss_devinfo_t *dp, int maxlen)
37{
38 seq_oss_writeq_t *q;
39 snd_seq_client_pool_t pool;
40
41 if ((q = kcalloc(1, sizeof(*q), GFP_KERNEL)) == NULL)
42 return NULL;
43 q->dp = dp;
44 q->maxlen = maxlen;
45 spin_lock_init(&q->sync_lock);
46 q->sync_event_put = 0;
47 q->sync_time = 0;
48 init_waitqueue_head(&q->sync_sleep);
49
50 memset(&pool, 0, sizeof(pool));
51 pool.client = dp->cseq;
52 pool.output_pool = maxlen;
53 pool.output_room = maxlen / 2;
54
55 snd_seq_oss_control(dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
56
57 return q;
58}
59
60/*
61 * delete the write queue
62 */
63void
64snd_seq_oss_writeq_delete(seq_oss_writeq_t *q)
65{
66 snd_seq_oss_writeq_clear(q); /* to be sure */
67 kfree(q);
68}
69
70
71/*
72 * reset the write queue
73 */
74void
75snd_seq_oss_writeq_clear(seq_oss_writeq_t *q)
76{
77 snd_seq_remove_events_t reset;
78
79 memset(&reset, 0, sizeof(reset));
80 reset.remove_mode = SNDRV_SEQ_REMOVE_OUTPUT; /* remove all */
81 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_REMOVE_EVENTS, &reset);
82
83 /* wake up sleepers if any */
84 snd_seq_oss_writeq_wakeup(q, 0);
85}
86
87/*
88 * wait until the write buffer has enough room
89 */
90int
91snd_seq_oss_writeq_sync(seq_oss_writeq_t *q)
92{
93 seq_oss_devinfo_t *dp = q->dp;
94 abstime_t time;
95
96 time = snd_seq_oss_timer_cur_tick(dp->timer);
97 if (q->sync_time >= time)
98 return 0; /* already finished */
99
100 if (! q->sync_event_put) {
101 snd_seq_event_t ev;
102 evrec_t *rec;
103
104 /* put echoback event */
105 memset(&ev, 0, sizeof(ev));
106 ev.flags = 0;
107 ev.type = SNDRV_SEQ_EVENT_ECHO;
108 ev.time.tick = time;
109 /* echo back to itself */
110 snd_seq_oss_fill_addr(dp, &ev, dp->addr.client, dp->addr.port);
111 rec = (evrec_t*)&ev.data;
112 rec->t.code = SEQ_SYNCTIMER;
113 rec->t.time = time;
114 q->sync_event_put = 1;
115 snd_seq_kernel_client_enqueue_blocking(dp->cseq, &ev, NULL, 0, 0);
116 }
117
118 wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
119 if (signal_pending(current))
120 /* interrupted - return 0 to finish sync */
121 q->sync_event_put = 0;
122 if (! q->sync_event_put || q->sync_time >= time)
123 return 0;
124 return 1;
125}
126
127/*
128 * wake up sync - echo event was catched
129 */
130void
131snd_seq_oss_writeq_wakeup(seq_oss_writeq_t *q, abstime_t time)
132{
133 unsigned long flags;
134
135 spin_lock_irqsave(&q->sync_lock, flags);
136 q->sync_time = time;
137 q->sync_event_put = 0;
138 if (waitqueue_active(&q->sync_sleep)) {
139 wake_up(&q->sync_sleep);
140 }
141 spin_unlock_irqrestore(&q->sync_lock, flags);
142}
143
144
145/*
146 * return the unused pool size
147 */
148int
149snd_seq_oss_writeq_get_free_size(seq_oss_writeq_t *q)
150{
151 snd_seq_client_pool_t pool;
152 pool.client = q->dp->cseq;
153 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
154 return pool.output_free;
155}
156
157
158/*
159 * set output threshold size from ioctl
160 */
161void
162snd_seq_oss_writeq_set_output(seq_oss_writeq_t *q, int val)
163{
164 snd_seq_client_pool_t pool;
165 pool.client = q->dp->cseq;
166 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, &pool);
167 pool.output_room = val;
168 snd_seq_oss_control(q->dp, SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, &pool);
169}
170
diff --git a/sound/core/seq/oss/seq_oss_writeq.h b/sound/core/seq/oss/seq_oss_writeq.h
new file mode 100644
index 000000000000..6a13c85e2399
--- /dev/null
+++ b/sound/core/seq/oss/seq_oss_writeq.h
@@ -0,0 +1,50 @@
1/*
2 * OSS compatible sequencer driver
3 * write priority queue
4 *
5 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#ifndef __SEQ_OSS_WRITEQ_H
23#define __SEQ_OSS_WRITEQ_H
24
25#include "seq_oss_device.h"
26
27
28struct seq_oss_writeq_t {
29 seq_oss_devinfo_t *dp;
30 int maxlen;
31 abstime_t sync_time;
32 int sync_event_put;
33 wait_queue_head_t sync_sleep;
34 spinlock_t sync_lock;
35};
36
37
38/*
39 * seq_oss_writeq.c
40 */
41seq_oss_writeq_t *snd_seq_oss_writeq_new(seq_oss_devinfo_t *dp, int maxlen);
42void snd_seq_oss_writeq_delete(seq_oss_writeq_t *q);
43void snd_seq_oss_writeq_clear(seq_oss_writeq_t *q);
44int snd_seq_oss_writeq_sync(seq_oss_writeq_t *q);
45void snd_seq_oss_writeq_wakeup(seq_oss_writeq_t *q, abstime_t time);
46int snd_seq_oss_writeq_get_free_size(seq_oss_writeq_t *q);
47void snd_seq_oss_writeq_set_output(seq_oss_writeq_t *q, int size);
48
49
50#endif
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
new file mode 100644
index 000000000000..7449d2a62629
--- /dev/null
+++ b/sound/core/seq/seq.c
@@ -0,0 +1,147 @@
1/*
2 * ALSA sequencer main module
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
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/moduleparam.h>
25#include <sound/core.h>
26#include <sound/initval.h>
27
28#include <sound/seq_kernel.h>
29#include "seq_clientmgr.h"
30#include "seq_memory.h"
31#include "seq_queue.h"
32#include "seq_lock.h"
33#include "seq_timer.h"
34#include "seq_system.h"
35#include "seq_info.h"
36#include <sound/seq_device.h>
37
38#if defined(CONFIG_SND_SEQ_DUMMY_MODULE)
39int seq_client_load[64] = {[0] = SNDRV_SEQ_CLIENT_DUMMY, [1 ... 63] = -1};
40#else
41int seq_client_load[64] = {[0 ... 63] = -1};
42#endif
43int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL;
44int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE;
45int seq_default_timer_card = -1;
46int seq_default_timer_device = SNDRV_TIMER_GLOBAL_SYSTEM;
47int seq_default_timer_subdevice = 0;
48int seq_default_timer_resolution = 0; /* Hz */
49
50MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@suse.cz>");
51MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer.");
52MODULE_LICENSE("GPL");
53
54module_param_array(seq_client_load, int, NULL, 0444);
55MODULE_PARM_DESC(seq_client_load, "The numbers of global (system) clients to load through kmod.");
56module_param(seq_default_timer_class, int, 0644);
57MODULE_PARM_DESC(seq_default_timer_class, "The default timer class.");
58module_param(seq_default_timer_sclass, int, 0644);
59MODULE_PARM_DESC(seq_default_timer_sclass, "The default timer slave class.");
60module_param(seq_default_timer_card, int, 0644);
61MODULE_PARM_DESC(seq_default_timer_card, "The default timer card number.");
62module_param(seq_default_timer_device, int, 0644);
63MODULE_PARM_DESC(seq_default_timer_device, "The default timer device number.");
64module_param(seq_default_timer_subdevice, int, 0644);
65MODULE_PARM_DESC(seq_default_timer_subdevice, "The default timer subdevice number.");
66module_param(seq_default_timer_resolution, int, 0644);
67MODULE_PARM_DESC(seq_default_timer_resolution, "The default timer resolution in Hz.");
68
69/*
70 * INIT PART
71 */
72
73static int __init alsa_seq_init(void)
74{
75 int err;
76
77 snd_seq_autoload_lock();
78 if ((err = client_init_data()) < 0)
79 goto error;
80
81 /* init memory, room for selected events */
82 if ((err = snd_sequencer_memory_init()) < 0)
83 goto error;
84
85 /* init event queues */
86 if ((err = snd_seq_queues_init()) < 0)
87 goto error;
88
89 /* register sequencer device */
90 if ((err = snd_sequencer_device_init()) < 0)
91 goto error;
92
93 /* register proc interface */
94 if ((err = snd_seq_info_init()) < 0)
95 goto error;
96
97 /* register our internal client */
98 if ((err = snd_seq_system_client_init()) < 0)
99 goto error;
100
101 error:
102 snd_seq_autoload_unlock();
103 return err;
104}
105
106static void __exit alsa_seq_exit(void)
107{
108 /* unregister our internal client */
109 snd_seq_system_client_done();
110
111 /* unregister proc interface */
112 snd_seq_info_done();
113
114 /* delete timing queues */
115 snd_seq_queues_delete();
116
117 /* unregister sequencer device */
118 snd_sequencer_device_done();
119
120 /* release event memory */
121 snd_sequencer_memory_done();
122}
123
124module_init(alsa_seq_init)
125module_exit(alsa_seq_exit)
126
127 /* seq_clientmgr.c */
128EXPORT_SYMBOL(snd_seq_create_kernel_client);
129EXPORT_SYMBOL(snd_seq_delete_kernel_client);
130EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
131EXPORT_SYMBOL(snd_seq_kernel_client_enqueue_blocking);
132EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
133EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
134EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
135EXPORT_SYMBOL(snd_seq_set_queue_tempo);
136 /* seq_memory.c */
137EXPORT_SYMBOL(snd_seq_expand_var_event);
138EXPORT_SYMBOL(snd_seq_dump_var_event);
139 /* seq_ports.c */
140EXPORT_SYMBOL(snd_seq_event_port_attach);
141EXPORT_SYMBOL(snd_seq_event_port_detach);
142 /* seq_lock.c */
143#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
144/*EXPORT_SYMBOL(snd_seq_sleep_in_lock);*/
145/*EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);*/
146EXPORT_SYMBOL(snd_use_lock_sync_helper);
147#endif
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
new file mode 100644
index 000000000000..d8f76afd284b
--- /dev/null
+++ b/sound/core/seq/seq_clientmgr.c
@@ -0,0 +1,2503 @@
1/*
2 * ALSA sequencer Client Manager
3 * Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl>
4 * Jaroslav Kysela <perex@suse.cz>
5 * Takashi Iwai <tiwai@suse.de>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sound/driver.h>
25#include <linux/init.h>
26#include <linux/smp_lock.h>
27#include <linux/slab.h>
28#include <sound/core.h>
29#include <sound/minors.h>
30#include <linux/kmod.h>
31
32#include <sound/seq_kernel.h>
33#include "seq_clientmgr.h"
34#include "seq_memory.h"
35#include "seq_queue.h"
36#include "seq_timer.h"
37#include "seq_info.h"
38#include "seq_system.h"
39#include <sound/seq_device.h>
40#ifdef CONFIG_COMPAT
41#include <linux/compat.h>
42#endif
43
44/* Client Manager
45
46 * this module handles the connections of userland and kernel clients
47 *
48 */
49
50#define SNDRV_SEQ_LFLG_INPUT 0x0001
51#define SNDRV_SEQ_LFLG_OUTPUT 0x0002
52#define SNDRV_SEQ_LFLG_OPEN (SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
53
54static DEFINE_SPINLOCK(clients_lock);
55static DECLARE_MUTEX(register_mutex);
56
57/*
58 * client table
59 */
60static char clienttablock[SNDRV_SEQ_MAX_CLIENTS];
61static client_t *clienttab[SNDRV_SEQ_MAX_CLIENTS];
62static usage_t client_usage;
63
64/*
65 * prototypes
66 */
67static int bounce_error_event(client_t *client, snd_seq_event_t *event, int err, int atomic, int hop);
68static int snd_seq_deliver_single_event(client_t *client, snd_seq_event_t *event, int filter, int atomic, int hop);
69
70/*
71 */
72
73static inline mm_segment_t snd_enter_user(void)
74{
75 mm_segment_t fs = get_fs();
76 set_fs(get_ds());
77 return fs;
78}
79
80static inline void snd_leave_user(mm_segment_t fs)
81{
82 set_fs(fs);
83}
84
85/*
86 */
87static inline unsigned short snd_seq_file_flags(struct file *file)
88{
89 switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
90 case FMODE_WRITE:
91 return SNDRV_SEQ_LFLG_OUTPUT;
92 case FMODE_READ:
93 return SNDRV_SEQ_LFLG_INPUT;
94 default:
95 return SNDRV_SEQ_LFLG_OPEN;
96 }
97}
98
99static inline int snd_seq_write_pool_allocated(client_t *client)
100{
101 return snd_seq_total_cells(client->pool) > 0;
102}
103
104/* return pointer to client structure for specified id */
105static client_t *clientptr(int clientid)
106{
107 if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
108 snd_printd("Seq: oops. Trying to get pointer to client %d\n", clientid);
109 return NULL;
110 }
111 return clienttab[clientid];
112}
113
114extern int seq_client_load[];
115
116client_t *snd_seq_client_use_ptr(int clientid)
117{
118 unsigned long flags;
119 client_t *client;
120
121 if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
122 snd_printd("Seq: oops. Trying to get pointer to client %d\n", clientid);
123 return NULL;
124 }
125 spin_lock_irqsave(&clients_lock, flags);
126 client = clientptr(clientid);
127 if (client)
128 goto __lock;
129 if (clienttablock[clientid]) {
130 spin_unlock_irqrestore(&clients_lock, flags);
131 return NULL;
132 }
133 spin_unlock_irqrestore(&clients_lock, flags);
134#ifdef CONFIG_KMOD
135 if (!in_interrupt() && current->fs->root) {
136 static char client_requested[64];
137 static char card_requested[SNDRV_CARDS];
138 if (clientid < 64) {
139 int idx;
140
141 if (! client_requested[clientid] && current->fs->root) {
142 client_requested[clientid] = 1;
143 for (idx = 0; idx < 64; idx++) {
144 if (seq_client_load[idx] < 0)
145 break;
146 if (seq_client_load[idx] == clientid) {
147 request_module("snd-seq-client-%i", clientid);
148 break;
149 }
150 }
151 }
152 } else if (clientid >= 64 && clientid < 128) {
153 int card = (clientid - 64) / 8;
154 if (card < snd_ecards_limit) {
155 if (! card_requested[card]) {
156 card_requested[card] = 1;
157 snd_request_card(card);
158 }
159 snd_seq_device_load_drivers();
160 }
161 }
162 spin_lock_irqsave(&clients_lock, flags);
163 client = clientptr(clientid);
164 if (client)
165 goto __lock;
166 spin_unlock_irqrestore(&clients_lock, flags);
167 }
168#endif
169 return NULL;
170
171 __lock:
172 snd_use_lock_use(&client->use_lock);
173 spin_unlock_irqrestore(&clients_lock, flags);
174 return client;
175}
176
177static void usage_alloc(usage_t * res, int num)
178{
179 res->cur += num;
180 if (res->cur > res->peak)
181 res->peak = res->cur;
182}
183
184static void usage_free(usage_t * res, int num)
185{
186 res->cur -= num;
187}
188
189/* initialise data structures */
190int __init client_init_data(void)
191{
192 /* zap out the client table */
193 memset(&clienttablock, 0, sizeof(clienttablock));
194 memset(&clienttab, 0, sizeof(clienttab));
195 return 0;
196}
197
198
199static client_t *seq_create_client1(int client_index, int poolsize)
200{
201 unsigned long flags;
202 int c;
203 client_t *client;
204
205 /* init client data */
206 client = kcalloc(1, sizeof(*client), GFP_KERNEL);
207 if (client == NULL)
208 return NULL;
209 client->pool = snd_seq_pool_new(poolsize);
210 if (client->pool == NULL) {
211 kfree(client);
212 return NULL;
213 }
214 client->type = NO_CLIENT;
215 snd_use_lock_init(&client->use_lock);
216 rwlock_init(&client->ports_lock);
217 init_MUTEX(&client->ports_mutex);
218 INIT_LIST_HEAD(&client->ports_list_head);
219
220 /* find free slot in the client table */
221 spin_lock_irqsave(&clients_lock, flags);
222 if (client_index < 0) {
223 for (c = 128; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
224 if (clienttab[c] || clienttablock[c])
225 continue;
226 clienttab[client->number = c] = client;
227 spin_unlock_irqrestore(&clients_lock, flags);
228 return client;
229 }
230 } else {
231 if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
232 clienttab[client->number = client_index] = client;
233 spin_unlock_irqrestore(&clients_lock, flags);
234 return client;
235 }
236 }
237 spin_unlock_irqrestore(&clients_lock, flags);
238 snd_seq_pool_delete(&client->pool);
239 kfree(client);
240 return NULL; /* no free slot found or busy, return failure code */
241}
242
243
244static int seq_free_client1(client_t *client)
245{
246 unsigned long flags;
247
248 snd_assert(client != NULL, return -EINVAL);
249 snd_seq_delete_all_ports(client);
250 snd_seq_queue_client_leave(client->number);
251 spin_lock_irqsave(&clients_lock, flags);
252 clienttablock[client->number] = 1;
253 clienttab[client->number] = NULL;
254 spin_unlock_irqrestore(&clients_lock, flags);
255 snd_use_lock_sync(&client->use_lock);
256 snd_seq_queue_client_termination(client->number);
257 if (client->pool)
258 snd_seq_pool_delete(&client->pool);
259 spin_lock_irqsave(&clients_lock, flags);
260 clienttablock[client->number] = 0;
261 spin_unlock_irqrestore(&clients_lock, flags);
262 return 0;
263}
264
265
266static void seq_free_client(client_t * client)
267{
268 down(&register_mutex);
269 switch (client->type) {
270 case NO_CLIENT:
271 snd_printk(KERN_WARNING "Seq: Trying to free unused client %d\n", client->number);
272 break;
273 case USER_CLIENT:
274 case KERNEL_CLIENT:
275 seq_free_client1(client);
276 usage_free(&client_usage, 1);
277 break;
278
279 default:
280 snd_printk(KERN_ERR "Seq: Trying to free client %d with undefined type = %d\n", client->number, client->type);
281 }
282 up(&register_mutex);
283
284 snd_seq_system_client_ev_client_exit(client->number);
285}
286
287
288
289/* -------------------------------------------------------- */
290
291/* create a user client */
292static int snd_seq_open(struct inode *inode, struct file *file)
293{
294 int c, mode; /* client id */
295 client_t *client;
296 user_client_t *user;
297
298 if (down_interruptible(&register_mutex))
299 return -ERESTARTSYS;
300 client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
301 if (client == NULL) {
302 up(&register_mutex);
303 return -ENOMEM; /* failure code */
304 }
305
306 mode = snd_seq_file_flags(file);
307 if (mode & SNDRV_SEQ_LFLG_INPUT)
308 client->accept_input = 1;
309 if (mode & SNDRV_SEQ_LFLG_OUTPUT)
310 client->accept_output = 1;
311
312 user = &client->data.user;
313 user->fifo = NULL;
314 user->fifo_pool_size = 0;
315
316 if (mode & SNDRV_SEQ_LFLG_INPUT) {
317 user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS;
318 user->fifo = snd_seq_fifo_new(user->fifo_pool_size);
319 if (user->fifo == NULL) {
320 seq_free_client1(client);
321 kfree(client);
322 up(&register_mutex);
323 return -ENOMEM;
324 }
325 }
326
327 usage_alloc(&client_usage, 1);
328 client->type = USER_CLIENT;
329 up(&register_mutex);
330
331 c = client->number;
332 file->private_data = client;
333
334 /* fill client data */
335 user->file = file;
336 sprintf(client->name, "Client-%d", c);
337
338 /* make others aware this new client */
339 snd_seq_system_client_ev_client_start(c);
340
341 return 0;
342}
343
344/* delete a user client */
345static int snd_seq_release(struct inode *inode, struct file *file)
346{
347 client_t *client = (client_t *) file->private_data;
348
349 if (client) {
350 seq_free_client(client);
351 if (client->data.user.fifo)
352 snd_seq_fifo_delete(&client->data.user.fifo);
353 kfree(client);
354 }
355
356 return 0;
357}
358
359
360/* handle client read() */
361/* possible error values:
362 * -ENXIO invalid client or file open mode
363 * -ENOSPC FIFO overflow (the flag is cleared after this error report)
364 * -EINVAL no enough user-space buffer to write the whole event
365 * -EFAULT seg. fault during copy to user space
366 */
367static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
368{
369 client_t *client = (client_t *) file->private_data;
370 fifo_t *fifo;
371 int err;
372 long result = 0;
373 snd_seq_event_cell_t *cell;
374
375 if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT))
376 return -ENXIO;
377
378 if (!access_ok(VERIFY_WRITE, buf, count))
379 return -EFAULT;
380
381 /* check client structures are in place */
382 snd_assert(client != NULL, return -ENXIO);
383
384 if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
385 return -ENXIO;
386
387 if (atomic_read(&fifo->overflow) > 0) {
388 /* buffer overflow is detected */
389 snd_seq_fifo_clear(fifo);
390 /* return error code */
391 return -ENOSPC;
392 }
393
394 cell = NULL;
395 err = 0;
396 snd_seq_fifo_lock(fifo);
397
398 /* while data available in queue */
399 while (count >= sizeof(snd_seq_event_t)) {
400 int nonblock;
401
402 nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
403 if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) {
404 break;
405 }
406 if (snd_seq_ev_is_variable(&cell->event)) {
407 snd_seq_event_t tmpev;
408 tmpev = cell->event;
409 tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
410 if (copy_to_user(buf, &tmpev, sizeof(snd_seq_event_t))) {
411 err = -EFAULT;
412 break;
413 }
414 count -= sizeof(snd_seq_event_t);
415 buf += sizeof(snd_seq_event_t);
416 err = snd_seq_expand_var_event(&cell->event, count, (char *)buf, 0, sizeof(snd_seq_event_t));
417 if (err < 0)
418 break;
419 result += err;
420 count -= err;
421 buf += err;
422 } else {
423 if (copy_to_user(buf, &cell->event, sizeof(snd_seq_event_t))) {
424 err = -EFAULT;
425 break;
426 }
427 count -= sizeof(snd_seq_event_t);
428 buf += sizeof(snd_seq_event_t);
429 }
430 snd_seq_cell_free(cell);
431 cell = NULL; /* to be sure */
432 result += sizeof(snd_seq_event_t);
433 }
434
435 if (err < 0) {
436 if (cell)
437 snd_seq_fifo_cell_putback(fifo, cell);
438 if (err == -EAGAIN && result > 0)
439 err = 0;
440 }
441 snd_seq_fifo_unlock(fifo);
442
443 return (err < 0) ? err : result;
444}
445
446
447/*
448 * check access permission to the port
449 */
450static int check_port_perm(client_port_t *port, unsigned int flags)
451{
452 if ((port->capability & flags) != flags)
453 return 0;
454 return flags;
455}
456
457/*
458 * check if the destination client is available, and return the pointer
459 * if filter is non-zero, client filter bitmap is tested.
460 */
461static client_t *get_event_dest_client(snd_seq_event_t *event, int filter)
462{
463 client_t *dest;
464
465 dest = snd_seq_client_use_ptr(event->dest.client);
466 if (dest == NULL)
467 return NULL;
468 if (! dest->accept_input)
469 goto __not_avail;
470 if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) &&
471 ! test_bit(event->type, dest->event_filter))
472 goto __not_avail;
473 if (filter && !(dest->filter & filter))
474 goto __not_avail;
475
476 return dest; /* ok - accessible */
477__not_avail:
478 snd_seq_client_unlock(dest);
479 return NULL;
480}
481
482
483/*
484 * Return the error event.
485 *
486 * If the receiver client is a user client, the original event is
487 * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. If
488 * the original event is also variable length, the external data is
489 * copied after the event record.
490 * If the receiver client is a kernel client, the original event is
491 * quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra
492 * kmalloc.
493 */
494static int bounce_error_event(client_t *client, snd_seq_event_t *event,
495 int err, int atomic, int hop)
496{
497 snd_seq_event_t bounce_ev;
498 int result;
499
500 if (client == NULL ||
501 ! (client->filter & SNDRV_SEQ_FILTER_BOUNCE) ||
502 ! client->accept_input)
503 return 0; /* ignored */
504
505 /* set up quoted error */
506 memset(&bounce_ev, 0, sizeof(bounce_ev));
507 bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;
508 bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
509 bounce_ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
510 bounce_ev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
511 bounce_ev.source.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
512 bounce_ev.dest.client = client->number;
513 bounce_ev.dest.port = event->source.port;
514 bounce_ev.data.quote.origin = event->dest;
515 bounce_ev.data.quote.event = event;
516 bounce_ev.data.quote.value = -err; /* use positive value */
517 result = snd_seq_deliver_single_event(NULL, &bounce_ev, 0, atomic, hop + 1);
518 if (result < 0) {
519 client->event_lost++;
520 return result;
521 }
522
523 return result;
524}
525
526
527/*
528 * rewrite the time-stamp of the event record with the curren time
529 * of the given queue.
530 * return non-zero if updated.
531 */
532static int update_timestamp_of_queue(snd_seq_event_t *event, int queue, int real_time)
533{
534 queue_t *q;
535
536 q = queueptr(queue);
537 if (! q)
538 return 0;
539 event->queue = queue;
540 event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
541 if (real_time) {
542 event->time.time = snd_seq_timer_get_cur_time(q->timer);
543 event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
544 } else {
545 event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
546 event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
547 }
548 queuefree(q);
549 return 1;
550}
551
552
553/*
554 * deliver an event to the specified destination.
555 * if filter is non-zero, client filter bitmap is tested.
556 *
557 * RETURN VALUE: 0 : if succeeded
558 * <0 : error
559 */
560static int snd_seq_deliver_single_event(client_t *client,
561 snd_seq_event_t *event,
562 int filter, int atomic, int hop)
563{
564 client_t *dest = NULL;
565 client_port_t *dest_port = NULL;
566 int result = -ENOENT;
567 int direct;
568
569 direct = snd_seq_ev_is_direct(event);
570
571 dest = get_event_dest_client(event, filter);
572 if (dest == NULL)
573 goto __skip;
574 dest_port = snd_seq_port_use_ptr(dest, event->dest.port);
575 if (dest_port == NULL)
576 goto __skip;
577
578 /* check permission */
579 if (! check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) {
580 result = -EPERM;
581 goto __skip;
582 }
583
584 if (dest_port->timestamping)
585 update_timestamp_of_queue(event, dest_port->time_queue,
586 dest_port->time_real);
587
588 switch (dest->type) {
589 case USER_CLIENT:
590 if (dest->data.user.fifo)
591 result = snd_seq_fifo_event_in(dest->data.user.fifo, event);
592 break;
593
594 case KERNEL_CLIENT:
595 if (dest_port->event_input == NULL)
596 break;
597 result = dest_port->event_input(event, direct, dest_port->private_data, atomic, hop);
598 break;
599 default:
600 break;
601 }
602
603 __skip:
604 if (dest_port)
605 snd_seq_port_unlock(dest_port);
606 if (dest)
607 snd_seq_client_unlock(dest);
608
609 if (result < 0 && !direct) {
610 result = bounce_error_event(client, event, result, atomic, hop);
611 }
612 return result;
613}
614
615
616/*
617 * send the event to all subscribers:
618 */
619static int deliver_to_subscribers(client_t *client,
620 snd_seq_event_t *event,
621 int atomic, int hop)
622{
623 subscribers_t *subs;
624 int err = 0, num_ev = 0;
625 snd_seq_event_t event_saved;
626 client_port_t *src_port;
627 struct list_head *p;
628 port_subs_info_t *grp;
629
630 src_port = snd_seq_port_use_ptr(client, event->source.port);
631 if (src_port == NULL)
632 return -EINVAL; /* invalid source port */
633 /* save original event record */
634 event_saved = *event;
635 grp = &src_port->c_src;
636
637 /* lock list */
638 if (atomic)
639 read_lock(&grp->list_lock);
640 else
641 down_read(&grp->list_mutex);
642 list_for_each(p, &grp->list_head) {
643 subs = list_entry(p, subscribers_t, src_list);
644 event->dest = subs->info.dest;
645 if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
646 /* convert time according to flag with subscription */
647 update_timestamp_of_queue(event, subs->info.queue,
648 subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
649 err = snd_seq_deliver_single_event(client, event,
650 0, atomic, hop);
651 if (err < 0)
652 break;
653 num_ev++;
654 /* restore original event record */
655 *event = event_saved;
656 }
657 if (atomic)
658 read_unlock(&grp->list_lock);
659 else
660 up_read(&grp->list_mutex);
661 *event = event_saved; /* restore */
662 snd_seq_port_unlock(src_port);
663 return (err < 0) ? err : num_ev;
664}
665
666
667#ifdef SUPPORT_BROADCAST
668/*
669 * broadcast to all ports:
670 */
671static int port_broadcast_event(client_t *client,
672 snd_seq_event_t *event,
673 int atomic, int hop)
674{
675 int num_ev = 0, err = 0;
676 client_t *dest_client;
677 struct list_head *p;
678
679 dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
680 if (dest_client == NULL)
681 return 0; /* no matching destination */
682
683 read_lock(&dest_client->ports_lock);
684 list_for_each(p, &dest_client->ports_list_head) {
685 client_port_t *port = list_entry(p, client_port_t, list);
686 event->dest.port = port->addr.port;
687 /* pass NULL as source client to avoid error bounce */
688 err = snd_seq_deliver_single_event(NULL, event,
689 SNDRV_SEQ_FILTER_BROADCAST,
690 atomic, hop);
691 if (err < 0)
692 break;
693 num_ev++;
694 }
695 read_unlock(&dest_client->ports_lock);
696 snd_seq_client_unlock(dest_client);
697 event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
698 return (err < 0) ? err : num_ev;
699}
700
701/*
702 * send the event to all clients:
703 * if destination port is also ADDRESS_BROADCAST, deliver to all ports.
704 */
705static int broadcast_event(client_t *client,
706 snd_seq_event_t *event, int atomic, int hop)
707{
708 int err = 0, num_ev = 0;
709 int dest;
710 snd_seq_addr_t addr;
711
712 addr = event->dest; /* save */
713
714 for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) {
715 /* don't send to itself */
716 if (dest == client->number)
717 continue;
718 event->dest.client = dest;
719 event->dest.port = addr.port;
720 if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST)
721 err = port_broadcast_event(client, event, atomic, hop);
722 else
723 /* pass NULL as source client to avoid error bounce */
724 err = snd_seq_deliver_single_event(NULL, event,
725 SNDRV_SEQ_FILTER_BROADCAST,
726 atomic, hop);
727 if (err < 0)
728 break;
729 num_ev += err;
730 }
731 event->dest = addr; /* restore */
732 return (err < 0) ? err : num_ev;
733}
734
735
736/* multicast - not supported yet */
737static int multicast_event(client_t *client, snd_seq_event_t *event,
738 int atomic, int hop)
739{
740 snd_printd("seq: multicast not supported yet.\n");
741 return 0; /* ignored */
742}
743#endif /* SUPPORT_BROADCAST */
744
745
746/* deliver an event to the destination port(s).
747 * if the event is to subscribers or broadcast, the event is dispatched
748 * to multiple targets.
749 *
750 * RETURN VALUE: n > 0 : the number of delivered events.
751 * n == 0 : the event was not passed to any client.
752 * n < 0 : error - event was not processed.
753 */
754static int snd_seq_deliver_event(client_t *client, snd_seq_event_t *event,
755 int atomic, int hop)
756{
757 int result;
758
759 hop++;
760 if (hop >= SNDRV_SEQ_MAX_HOPS) {
761 snd_printd("too long delivery path (%d:%d->%d:%d)\n",
762 event->source.client, event->source.port,
763 event->dest.client, event->dest.port);
764 return -EMLINK;
765 }
766
767 if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS ||
768 event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)
769 result = deliver_to_subscribers(client, event, atomic, hop);
770#ifdef SUPPORT_BROADCAST
771 else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST ||
772 event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST)
773 result = broadcast_event(client, event, atomic, hop);
774 else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS)
775 result = multicast_event(client, event, atomic, hop);
776 else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST)
777 result = port_broadcast_event(client, event, atomic, hop);
778#endif
779 else
780 result = snd_seq_deliver_single_event(client, event, 0, atomic, hop);
781
782 return result;
783}
784
785/*
786 * dispatch an event cell:
787 * This function is called only from queue check routines in timer
788 * interrupts or after enqueued.
789 * The event cell shall be released or re-queued in this function.
790 *
791 * RETURN VALUE: n > 0 : the number of delivered events.
792 * n == 0 : the event was not passed to any client.
793 * n < 0 : error - event was not processed.
794 */
795int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop)
796{
797 client_t *client;
798 int result;
799
800 snd_assert(cell != NULL, return -EINVAL);
801
802 client = snd_seq_client_use_ptr(cell->event.source.client);
803 if (client == NULL) {
804 snd_seq_cell_free(cell); /* release this cell */
805 return -EINVAL;
806 }
807
808 if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) {
809 /* NOTE event:
810 * the event cell is re-used as a NOTE-OFF event and
811 * enqueued again.
812 */
813 snd_seq_event_t tmpev, *ev;
814
815 /* reserve this event to enqueue note-off later */
816 tmpev = cell->event;
817 tmpev.type = SNDRV_SEQ_EVENT_NOTEON;
818 result = snd_seq_deliver_event(client, &tmpev, atomic, hop);
819
820 /*
821 * This was originally a note event. We now re-use the
822 * cell for the note-off event.
823 */
824
825 ev = &cell->event;
826 ev->type = SNDRV_SEQ_EVENT_NOTEOFF;
827 ev->flags |= SNDRV_SEQ_PRIORITY_HIGH;
828
829 /* add the duration time */
830 switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) {
831 case SNDRV_SEQ_TIME_STAMP_TICK:
832 ev->time.tick += ev->data.note.duration;
833 break;
834 case SNDRV_SEQ_TIME_STAMP_REAL:
835 /* unit for duration is ms */
836 ev->time.time.tv_nsec += 1000000 * (ev->data.note.duration % 1000);
837 ev->time.time.tv_sec += ev->data.note.duration / 1000 +
838 ev->time.time.tv_nsec / 1000000000;
839 ev->time.time.tv_nsec %= 1000000000;
840 break;
841 }
842 ev->data.note.velocity = ev->data.note.off_velocity;
843
844 /* Now queue this cell as the note off event */
845 if (snd_seq_enqueue_event(cell, atomic, hop) < 0)
846 snd_seq_cell_free(cell); /* release this cell */
847
848 } else {
849 /* Normal events:
850 * event cell is freed after processing the event
851 */
852
853 result = snd_seq_deliver_event(client, &cell->event, atomic, hop);
854 snd_seq_cell_free(cell);
855 }
856
857 snd_seq_client_unlock(client);
858 return result;
859}
860
861
862/* Allocate a cell from client pool and enqueue it to queue:
863 * if pool is empty and blocking is TRUE, sleep until a new cell is
864 * available.
865 */
866static int snd_seq_client_enqueue_event(client_t *client,
867 snd_seq_event_t *event,
868 struct file *file, int blocking,
869 int atomic, int hop)
870{
871 snd_seq_event_cell_t *cell;
872 int err;
873
874 /* special queue values - force direct passing */
875 if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
876 event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
877 event->queue = SNDRV_SEQ_QUEUE_DIRECT;
878 } else
879#ifdef SUPPORT_BROADCAST
880 if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) {
881 event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST;
882 event->queue = SNDRV_SEQ_QUEUE_DIRECT;
883 }
884#endif
885 if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
886 /* check presence of source port */
887 client_port_t *src_port = snd_seq_port_use_ptr(client, event->source.port);
888 if (src_port == NULL)
889 return -EINVAL;
890 snd_seq_port_unlock(src_port);
891 }
892
893 /* direct event processing without enqueued */
894 if (snd_seq_ev_is_direct(event)) {
895 if (event->type == SNDRV_SEQ_EVENT_NOTE)
896 return -EINVAL; /* this event must be enqueued! */
897 return snd_seq_deliver_event(client, event, atomic, hop);
898 }
899
900 /* Not direct, normal queuing */
901 if (snd_seq_queue_is_used(event->queue, client->number) <= 0)
902 return -EINVAL; /* invalid queue */
903 if (! snd_seq_write_pool_allocated(client))
904 return -ENXIO; /* queue is not allocated */
905
906 /* allocate an event cell */
907 err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file);
908 if (err < 0)
909 return err;
910
911 /* we got a cell. enqueue it. */
912 if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) {
913 snd_seq_cell_free(cell);
914 return err;
915 }
916
917 return 0;
918}
919
920
921/*
922 * check validity of event type and data length.
923 * return non-zero if invalid.
924 */
925static int check_event_type_and_length(snd_seq_event_t *ev)
926{
927 switch (snd_seq_ev_length_type(ev)) {
928 case SNDRV_SEQ_EVENT_LENGTH_FIXED:
929 if (snd_seq_ev_is_variable_type(ev))
930 return -EINVAL;
931 break;
932 case SNDRV_SEQ_EVENT_LENGTH_VARIABLE:
933 if (! snd_seq_ev_is_variable_type(ev) ||
934 (ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK) >= SNDRV_SEQ_MAX_EVENT_LEN)
935 return -EINVAL;
936 break;
937 case SNDRV_SEQ_EVENT_LENGTH_VARUSR:
938 if (! snd_seq_ev_is_instr_type(ev) ||
939 ! snd_seq_ev_is_direct(ev))
940 return -EINVAL;
941 break;
942 }
943 return 0;
944}
945
946
947/* handle write() */
948/* possible error values:
949 * -ENXIO invalid client or file open mode
950 * -ENOMEM malloc failed
951 * -EFAULT seg. fault during copy from user space
952 * -EINVAL invalid event
953 * -EAGAIN no space in output pool
954 * -EINTR interrupts while sleep
955 * -EMLINK too many hops
956 * others depends on return value from driver callback
957 */
958static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
959{
960 client_t *client = (client_t *) file->private_data;
961 int written = 0, len;
962 int err = -EINVAL;
963 snd_seq_event_t event;
964
965 if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
966 return -ENXIO;
967
968 /* check client structures are in place */
969 snd_assert(client != NULL, return -ENXIO);
970
971 if (!client->accept_output || client->pool == NULL)
972 return -ENXIO;
973
974 /* allocate the pool now if the pool is not allocated yet */
975 if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
976 if (snd_seq_pool_init(client->pool) < 0)
977 return -ENOMEM;
978 }
979
980 /* only process whole events */
981 while (count >= sizeof(snd_seq_event_t)) {
982 /* Read in the event header from the user */
983 len = sizeof(event);
984 if (copy_from_user(&event, buf, len)) {
985 err = -EFAULT;
986 break;
987 }
988 event.source.client = client->number; /* fill in client number */
989 /* Check for extension data length */
990 if (check_event_type_and_length(&event)) {
991 err = -EINVAL;
992 break;
993 }
994
995 /* check for special events */
996 if (event.type == SNDRV_SEQ_EVENT_NONE)
997 goto __skip_event;
998 else if (snd_seq_ev_is_reserved(&event)) {
999 err = -EINVAL;
1000 break;
1001 }
1002
1003 if (snd_seq_ev_is_variable(&event)) {
1004 int extlen = event.data.ext.len & ~SNDRV_SEQ_EXT_MASK;
1005 if ((size_t)(extlen + len) > count) {
1006 /* back out, will get an error this time or next */
1007 err = -EINVAL;
1008 break;
1009 }
1010 /* set user space pointer */
1011 event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
1012 event.data.ext.ptr = (char*)buf + sizeof(snd_seq_event_t);
1013 len += extlen; /* increment data length */
1014 } else {
1015#ifdef CONFIG_COMPAT
1016 if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
1017 void *ptr = compat_ptr(event.data.raw32.d[1]);
1018 event.data.ext.ptr = ptr;
1019 }
1020#endif
1021 }
1022
1023 /* ok, enqueue it */
1024 err = snd_seq_client_enqueue_event(client, &event, file,
1025 !(file->f_flags & O_NONBLOCK),
1026 0, 0);
1027 if (err < 0)
1028 break;
1029
1030 __skip_event:
1031 /* Update pointers and counts */
1032 count -= len;
1033 buf += len;
1034 written += len;
1035 }
1036
1037 return written ? written : err;
1038}
1039
1040
1041/*
1042 * handle polling
1043 */
1044static unsigned int snd_seq_poll(struct file *file, poll_table * wait)
1045{
1046 client_t *client = (client_t *) file->private_data;
1047 unsigned int mask = 0;
1048
1049 /* check client structures are in place */
1050 snd_assert(client != NULL, return -ENXIO);
1051
1052 if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) &&
1053 client->data.user.fifo) {
1054
1055 /* check if data is available in the outqueue */
1056 if (snd_seq_fifo_poll_wait(client->data.user.fifo, file, wait))
1057 mask |= POLLIN | POLLRDNORM;
1058 }
1059
1060 if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) {
1061
1062 /* check if data is available in the pool */
1063 if (!snd_seq_write_pool_allocated(client) ||
1064 snd_seq_pool_poll_wait(client->pool, file, wait))
1065 mask |= POLLOUT | POLLWRNORM;
1066 }
1067
1068 return mask;
1069}
1070
1071
1072/*-----------------------------------------------------*/
1073
1074
1075/* SYSTEM_INFO ioctl() */
1076static int snd_seq_ioctl_system_info(client_t *client, void __user *arg)
1077{
1078 snd_seq_system_info_t info;
1079
1080 memset(&info, 0, sizeof(info));
1081 /* fill the info fields */
1082 info.queues = SNDRV_SEQ_MAX_QUEUES;
1083 info.clients = SNDRV_SEQ_MAX_CLIENTS;
1084 info.ports = 256; /* fixed limit */
1085 info.channels = 256; /* fixed limit */
1086 info.cur_clients = client_usage.cur;
1087 info.cur_queues = snd_seq_queue_get_cur_queues();
1088
1089 if (copy_to_user(arg, &info, sizeof(info)))
1090 return -EFAULT;
1091 return 0;
1092}
1093
1094
1095/* RUNNING_MODE ioctl() */
1096static int snd_seq_ioctl_running_mode(client_t *client, void __user *arg)
1097{
1098 struct sndrv_seq_running_info info;
1099 client_t *cptr;
1100 int err = 0;
1101
1102 if (copy_from_user(&info, arg, sizeof(info)))
1103 return -EFAULT;
1104
1105 /* requested client number */
1106 cptr = snd_seq_client_use_ptr(info.client);
1107 if (cptr == NULL)
1108 return -ENOENT; /* don't change !!! */
1109
1110#ifdef SNDRV_BIG_ENDIAN
1111 if (! info.big_endian) {
1112 err = -EINVAL;
1113 goto __err;
1114 }
1115#else
1116 if (info.big_endian) {
1117 err = -EINVAL;
1118 goto __err;
1119 }
1120
1121#endif
1122 if (info.cpu_mode > sizeof(long)) {
1123 err = -EINVAL;
1124 goto __err;
1125 }
1126 cptr->convert32 = (info.cpu_mode < sizeof(long));
1127 __err:
1128 snd_seq_client_unlock(cptr);
1129 return err;
1130}
1131
1132/* CLIENT_INFO ioctl() */
1133static void get_client_info(client_t *cptr, snd_seq_client_info_t *info)
1134{
1135 info->client = cptr->number;
1136
1137 /* fill the info fields */
1138 info->type = cptr->type;
1139 strcpy(info->name, cptr->name);
1140 info->filter = cptr->filter;
1141 info->event_lost = cptr->event_lost;
1142 memcpy(info->event_filter, cptr->event_filter, 32);
1143 info->num_ports = cptr->num_ports;
1144 memset(info->reserved, 0, sizeof(info->reserved));
1145}
1146
1147static int snd_seq_ioctl_get_client_info(client_t * client, void __user *arg)
1148{
1149 client_t *cptr;
1150 snd_seq_client_info_t client_info;
1151
1152 if (copy_from_user(&client_info, arg, sizeof(client_info)))
1153 return -EFAULT;
1154
1155 /* requested client number */
1156 cptr = snd_seq_client_use_ptr(client_info.client);
1157 if (cptr == NULL)
1158 return -ENOENT; /* don't change !!! */
1159
1160 get_client_info(cptr, &client_info);
1161 snd_seq_client_unlock(cptr);
1162
1163 if (copy_to_user(arg, &client_info, sizeof(client_info)))
1164 return -EFAULT;
1165 return 0;
1166}
1167
1168
1169/* CLIENT_INFO ioctl() */
1170static int snd_seq_ioctl_set_client_info(client_t * client, void __user *arg)
1171{
1172 snd_seq_client_info_t client_info;
1173
1174 if (copy_from_user(&client_info, arg, sizeof(client_info)))
1175 return -EFAULT;
1176
1177 /* it is not allowed to set the info fields for an another client */
1178 if (client->number != client_info.client)
1179 return -EPERM;
1180 /* also client type must be set now */
1181 if (client->type != client_info.type)
1182 return -EINVAL;
1183
1184 /* fill the info fields */
1185 if (client_info.name[0])
1186 strlcpy(client->name, client_info.name, sizeof(client->name));
1187
1188 client->filter = client_info.filter;
1189 client->event_lost = client_info.event_lost;
1190 memcpy(client->event_filter, client_info.event_filter, 32);
1191
1192 return 0;
1193}
1194
1195
1196/*
1197 * CREATE PORT ioctl()
1198 */
1199static int snd_seq_ioctl_create_port(client_t * client, void __user *arg)
1200{
1201 client_port_t *port;
1202 snd_seq_port_info_t info;
1203 snd_seq_port_callback_t *callback;
1204
1205 if (copy_from_user(&info, arg, sizeof(info)))
1206 return -EFAULT;
1207
1208 /* it is not allowed to create the port for an another client */
1209 if (info.addr.client != client->number)
1210 return -EPERM;
1211
1212 port = snd_seq_create_port(client, (info.flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info.addr.port : -1);
1213 if (port == NULL)
1214 return -ENOMEM;
1215
1216 if (client->type == USER_CLIENT && info.kernel) {
1217 snd_seq_delete_port(client, port->addr.port);
1218 return -EINVAL;
1219 }
1220 if (client->type == KERNEL_CLIENT) {
1221 if ((callback = info.kernel) != NULL) {
1222 if (callback->owner)
1223 port->owner = callback->owner;
1224 port->private_data = callback->private_data;
1225 port->private_free = callback->private_free;
1226 port->callback_all = callback->callback_all;
1227 port->event_input = callback->event_input;
1228 port->c_src.open = callback->subscribe;
1229 port->c_src.close = callback->unsubscribe;
1230 port->c_dest.open = callback->use;
1231 port->c_dest.close = callback->unuse;
1232 }
1233 }
1234
1235 info.addr = port->addr;
1236
1237 snd_seq_set_port_info(port, &info);
1238 snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
1239
1240 if (copy_to_user(arg, &info, sizeof(info)))
1241 return -EFAULT;
1242
1243 return 0;
1244}
1245
1246/*
1247 * DELETE PORT ioctl()
1248 */
1249static int snd_seq_ioctl_delete_port(client_t * client, void __user *arg)
1250{
1251 snd_seq_port_info_t info;
1252 int err;
1253
1254 /* set passed parameters */
1255 if (copy_from_user(&info, arg, sizeof(info)))
1256 return -EFAULT;
1257
1258 /* it is not allowed to remove the port for an another client */
1259 if (info.addr.client != client->number)
1260 return -EPERM;
1261
1262 err = snd_seq_delete_port(client, info.addr.port);
1263 if (err >= 0)
1264 snd_seq_system_client_ev_port_exit(client->number, info.addr.port);
1265 return err;
1266}
1267
1268
1269/*
1270 * GET_PORT_INFO ioctl() (on any client)
1271 */
1272static int snd_seq_ioctl_get_port_info(client_t *client, void __user *arg)
1273{
1274 client_t *cptr;
1275 client_port_t *port;
1276 snd_seq_port_info_t info;
1277
1278 if (copy_from_user(&info, arg, sizeof(info)))
1279 return -EFAULT;
1280 cptr = snd_seq_client_use_ptr(info.addr.client);
1281 if (cptr == NULL)
1282 return -ENXIO;
1283
1284 port = snd_seq_port_use_ptr(cptr, info.addr.port);
1285 if (port == NULL) {
1286 snd_seq_client_unlock(cptr);
1287 return -ENOENT; /* don't change */
1288 }
1289
1290 /* get port info */
1291 snd_seq_get_port_info(port, &info);
1292 snd_seq_port_unlock(port);
1293 snd_seq_client_unlock(cptr);
1294
1295 if (copy_to_user(arg, &info, sizeof(info)))
1296 return -EFAULT;
1297 return 0;
1298}
1299
1300
1301/*
1302 * SET_PORT_INFO ioctl() (only ports on this/own client)
1303 */
1304static int snd_seq_ioctl_set_port_info(client_t * client, void __user *arg)
1305{
1306 client_port_t *port;
1307 snd_seq_port_info_t info;
1308
1309 if (copy_from_user(&info, arg, sizeof(info)))
1310 return -EFAULT;
1311
1312 if (info.addr.client != client->number) /* only set our own ports ! */
1313 return -EPERM;
1314 port = snd_seq_port_use_ptr(client, info.addr.port);
1315 if (port) {
1316 snd_seq_set_port_info(port, &info);
1317 snd_seq_port_unlock(port);
1318 }
1319 return 0;
1320}
1321
1322
1323/*
1324 * port subscription (connection)
1325 */
1326#define PERM_RD (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
1327#define PERM_WR (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
1328
1329static int check_subscription_permission(client_t *client, client_port_t *sport,
1330 client_port_t *dport,
1331 snd_seq_port_subscribe_t *subs)
1332{
1333 if (client->number != subs->sender.client &&
1334 client->number != subs->dest.client) {
1335 /* connection by third client - check export permission */
1336 if (check_port_perm(sport, SNDRV_SEQ_PORT_CAP_NO_EXPORT))
1337 return -EPERM;
1338 if (check_port_perm(dport, SNDRV_SEQ_PORT_CAP_NO_EXPORT))
1339 return -EPERM;
1340 }
1341
1342 /* check read permission */
1343 /* if sender or receiver is the subscribing client itself,
1344 * no permission check is necessary
1345 */
1346 if (client->number != subs->sender.client) {
1347 if (! check_port_perm(sport, PERM_RD))
1348 return -EPERM;
1349 }
1350 /* check write permission */
1351 if (client->number != subs->dest.client) {
1352 if (! check_port_perm(dport, PERM_WR))
1353 return -EPERM;
1354 }
1355 return 0;
1356}
1357
1358/*
1359 * send an subscription notify event to user client:
1360 * client must be user client.
1361 */
1362int snd_seq_client_notify_subscription(int client, int port,
1363 snd_seq_port_subscribe_t *info, int evtype)
1364{
1365 snd_seq_event_t event;
1366
1367 memset(&event, 0, sizeof(event));
1368 event.type = evtype;
1369 event.data.connect.dest = info->dest;
1370 event.data.connect.sender = info->sender;
1371
1372 return snd_seq_system_notify(client, port, &event); /* non-atomic */
1373}
1374
1375
1376/*
1377 * add to port's subscription list IOCTL interface
1378 */
1379static int snd_seq_ioctl_subscribe_port(client_t * client, void __user *arg)
1380{
1381 int result = -EINVAL;
1382 client_t *receiver = NULL, *sender = NULL;
1383 client_port_t *sport = NULL, *dport = NULL;
1384 snd_seq_port_subscribe_t subs;
1385
1386 if (copy_from_user(&subs, arg, sizeof(subs)))
1387 return -EFAULT;
1388
1389 if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL)
1390 goto __end;
1391 if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL)
1392 goto __end;
1393 if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL)
1394 goto __end;
1395 if ((dport = snd_seq_port_use_ptr(receiver, subs.dest.port)) == NULL)
1396 goto __end;
1397
1398 result = check_subscription_permission(client, sport, dport, &subs);
1399 if (result < 0)
1400 goto __end;
1401
1402 /* connect them */
1403 result = snd_seq_port_connect(client, sender, sport, receiver, dport, &subs);
1404 if (! result) /* broadcast announce */
1405 snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
1406 &subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
1407 __end:
1408 if (sport)
1409 snd_seq_port_unlock(sport);
1410 if (dport)
1411 snd_seq_port_unlock(dport);
1412 if (sender)
1413 snd_seq_client_unlock(sender);
1414 if (receiver)
1415 snd_seq_client_unlock(receiver);
1416 return result;
1417}
1418
1419
1420/*
1421 * remove from port's subscription list
1422 */
1423static int snd_seq_ioctl_unsubscribe_port(client_t * client, void __user *arg)
1424{
1425 int result = -ENXIO;
1426 client_t *receiver = NULL, *sender = NULL;
1427 client_port_t *sport = NULL, *dport = NULL;
1428 snd_seq_port_subscribe_t subs;
1429
1430 if (copy_from_user(&subs, arg, sizeof(subs)))
1431 return -EFAULT;
1432
1433 if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL)
1434 goto __end;
1435 if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL)
1436 goto __end;
1437 if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL)
1438 goto __end;
1439 if ((dport = snd_seq_port_use_ptr(receiver, subs.dest.port)) == NULL)
1440 goto __end;
1441
1442 result = check_subscription_permission(client, sport, dport, &subs);
1443 if (result < 0)
1444 goto __end;
1445
1446 result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, &subs);
1447 if (! result) /* broadcast announce */
1448 snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
1449 &subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
1450 __end:
1451 if (sport)
1452 snd_seq_port_unlock(sport);
1453 if (dport)
1454 snd_seq_port_unlock(dport);
1455 if (sender)
1456 snd_seq_client_unlock(sender);
1457 if (receiver)
1458 snd_seq_client_unlock(receiver);
1459 return result;
1460}
1461
1462
1463/* CREATE_QUEUE ioctl() */
1464static int snd_seq_ioctl_create_queue(client_t *client, void __user *arg)
1465{
1466 snd_seq_queue_info_t info;
1467 int result;
1468 queue_t *q;
1469
1470 if (copy_from_user(&info, arg, sizeof(info)))
1471 return -EFAULT;
1472
1473 result = snd_seq_queue_alloc(client->number, info.locked, info.flags);
1474 if (result < 0)
1475 return result;
1476
1477 q = queueptr(result);
1478 if (q == NULL)
1479 return -EINVAL;
1480
1481 info.queue = q->queue;
1482 info.locked = q->locked;
1483 info.owner = q->owner;
1484
1485 /* set queue name */
1486 if (! info.name[0])
1487 snprintf(info.name, sizeof(info.name), "Queue-%d", q->queue);
1488 strlcpy(q->name, info.name, sizeof(q->name));
1489 queuefree(q);
1490
1491 if (copy_to_user(arg, &info, sizeof(info)))
1492 return -EFAULT;
1493
1494 return 0;
1495}
1496
1497/* DELETE_QUEUE ioctl() */
1498static int snd_seq_ioctl_delete_queue(client_t *client, void __user *arg)
1499{
1500 snd_seq_queue_info_t info;
1501
1502 if (copy_from_user(&info, arg, sizeof(info)))
1503 return -EFAULT;
1504
1505 return snd_seq_queue_delete(client->number, info.queue);
1506}
1507
1508/* GET_QUEUE_INFO ioctl() */
1509static int snd_seq_ioctl_get_queue_info(client_t *client, void __user *arg)
1510{
1511 snd_seq_queue_info_t info;
1512 queue_t *q;
1513
1514 if (copy_from_user(&info, arg, sizeof(info)))
1515 return -EFAULT;
1516
1517 q = queueptr(info.queue);
1518 if (q == NULL)
1519 return -EINVAL;
1520
1521 memset(&info, 0, sizeof(info));
1522 info.queue = q->queue;
1523 info.owner = q->owner;
1524 info.locked = q->locked;
1525 strlcpy(info.name, q->name, sizeof(info.name));
1526 queuefree(q);
1527
1528 if (copy_to_user(arg, &info, sizeof(info)))
1529 return -EFAULT;
1530
1531 return 0;
1532}
1533
1534/* SET_QUEUE_INFO ioctl() */
1535static int snd_seq_ioctl_set_queue_info(client_t *client, void __user *arg)
1536{
1537 snd_seq_queue_info_t info;
1538 queue_t *q;
1539
1540 if (copy_from_user(&info, arg, sizeof(info)))
1541 return -EFAULT;
1542
1543 if (info.owner != client->number)
1544 return -EINVAL;
1545
1546 /* change owner/locked permission */
1547 if (snd_seq_queue_check_access(info.queue, client->number)) {
1548 if (snd_seq_queue_set_owner(info.queue, client->number, info.locked) < 0)
1549 return -EPERM;
1550 if (info.locked)
1551 snd_seq_queue_use(info.queue, client->number, 1);
1552 } else {
1553 return -EPERM;
1554 }
1555
1556 q = queueptr(info.queue);
1557 if (! q)
1558 return -EINVAL;
1559 if (q->owner != client->number) {
1560 queuefree(q);
1561 return -EPERM;
1562 }
1563 strlcpy(q->name, info.name, sizeof(q->name));
1564 queuefree(q);
1565
1566 return 0;
1567}
1568
1569/* GET_NAMED_QUEUE ioctl() */
1570static int snd_seq_ioctl_get_named_queue(client_t *client, void __user *arg)
1571{
1572 snd_seq_queue_info_t info;
1573 queue_t *q;
1574
1575 if (copy_from_user(&info, arg, sizeof(info)))
1576 return -EFAULT;
1577
1578 q = snd_seq_queue_find_name(info.name);
1579 if (q == NULL)
1580 return -EINVAL;
1581 info.queue = q->queue;
1582 info.owner = q->owner;
1583 info.locked = q->locked;
1584 queuefree(q);
1585
1586 if (copy_to_user(arg, &info, sizeof(info)))
1587 return -EFAULT;
1588
1589 return 0;
1590}
1591
1592/* GET_QUEUE_STATUS ioctl() */
1593static int snd_seq_ioctl_get_queue_status(client_t * client, void __user *arg)
1594{
1595 snd_seq_queue_status_t status;
1596 queue_t *queue;
1597 seq_timer_t *tmr;
1598
1599 if (copy_from_user(&status, arg, sizeof(status)))
1600 return -EFAULT;
1601
1602 queue = queueptr(status.queue);
1603 if (queue == NULL)
1604 return -EINVAL;
1605 memset(&status, 0, sizeof(status));
1606 status.queue = queue->queue;
1607
1608 tmr = queue->timer;
1609 status.events = queue->tickq->cells + queue->timeq->cells;
1610
1611 status.time = snd_seq_timer_get_cur_time(tmr);
1612 status.tick = snd_seq_timer_get_cur_tick(tmr);
1613
1614 status.running = tmr->running;
1615
1616 status.flags = queue->flags;
1617 queuefree(queue);
1618
1619 if (copy_to_user(arg, &status, sizeof(status)))
1620 return -EFAULT;
1621 return 0;
1622}
1623
1624
1625/* GET_QUEUE_TEMPO ioctl() */
1626static int snd_seq_ioctl_get_queue_tempo(client_t * client, void __user *arg)
1627{
1628 snd_seq_queue_tempo_t tempo;
1629 queue_t *queue;
1630 seq_timer_t *tmr;
1631
1632 if (copy_from_user(&tempo, arg, sizeof(tempo)))
1633 return -EFAULT;
1634
1635 queue = queueptr(tempo.queue);
1636 if (queue == NULL)
1637 return -EINVAL;
1638 memset(&tempo, 0, sizeof(tempo));
1639 tempo.queue = queue->queue;
1640
1641 tmr = queue->timer;
1642
1643 tempo.tempo = tmr->tempo;
1644 tempo.ppq = tmr->ppq;
1645 tempo.skew_value = tmr->skew;
1646 tempo.skew_base = tmr->skew_base;
1647 queuefree(queue);
1648
1649 if (copy_to_user(arg, &tempo, sizeof(tempo)))
1650 return -EFAULT;
1651 return 0;
1652}
1653
1654
1655/* SET_QUEUE_TEMPO ioctl() */
1656int snd_seq_set_queue_tempo(int client, snd_seq_queue_tempo_t *tempo)
1657{
1658 if (!snd_seq_queue_check_access(tempo->queue, client))
1659 return -EPERM;
1660 return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
1661}
1662
1663static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
1664{
1665 int result;
1666 snd_seq_queue_tempo_t tempo;
1667
1668 if (copy_from_user(&tempo, arg, sizeof(tempo)))
1669 return -EFAULT;
1670
1671 result = snd_seq_set_queue_tempo(client->number, &tempo);
1672 return result < 0 ? result : 0;
1673}
1674
1675
1676/* GET_QUEUE_TIMER ioctl() */
1677static int snd_seq_ioctl_get_queue_timer(client_t * client, void __user *arg)
1678{
1679 snd_seq_queue_timer_t timer;
1680 queue_t *queue;
1681 seq_timer_t *tmr;
1682
1683 if (copy_from_user(&timer, arg, sizeof(timer)))
1684 return -EFAULT;
1685
1686 queue = queueptr(timer.queue);
1687 if (queue == NULL)
1688 return -EINVAL;
1689
1690 if (down_interruptible(&queue->timer_mutex)) {
1691 queuefree(queue);
1692 return -ERESTARTSYS;
1693 }
1694 tmr = queue->timer;
1695 memset(&timer, 0, sizeof(timer));
1696 timer.queue = queue->queue;
1697
1698 timer.type = tmr->type;
1699 if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {
1700 timer.u.alsa.id = tmr->alsa_id;
1701 timer.u.alsa.resolution = tmr->preferred_resolution;
1702 }
1703 up(&queue->timer_mutex);
1704 queuefree(queue);
1705
1706 if (copy_to_user(arg, &timer, sizeof(timer)))
1707 return -EFAULT;
1708 return 0;
1709}
1710
1711
1712/* SET_QUEUE_TIMER ioctl() */
1713static int snd_seq_ioctl_set_queue_timer(client_t * client, void __user *arg)
1714{
1715 int result = 0;
1716 snd_seq_queue_timer_t timer;
1717
1718 if (copy_from_user(&timer, arg, sizeof(timer)))
1719 return -EFAULT;
1720
1721 if (timer.type != SNDRV_SEQ_TIMER_ALSA)
1722 return -EINVAL;
1723
1724 if (snd_seq_queue_check_access(timer.queue, client->number)) {
1725 queue_t *q;
1726 seq_timer_t *tmr;
1727
1728 q = queueptr(timer.queue);
1729 if (q == NULL)
1730 return -ENXIO;
1731 if (down_interruptible(&q->timer_mutex)) {
1732 queuefree(q);
1733 return -ERESTARTSYS;
1734 }
1735 tmr = q->timer;
1736 snd_seq_queue_timer_close(timer.queue);
1737 tmr->type = timer.type;
1738 if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {
1739 tmr->alsa_id = timer.u.alsa.id;
1740 tmr->preferred_resolution = timer.u.alsa.resolution;
1741 }
1742 result = snd_seq_queue_timer_open(timer.queue);
1743 up(&q->timer_mutex);
1744 queuefree(q);
1745 } else {
1746 return -EPERM;
1747 }
1748
1749 return result;
1750}
1751
1752
1753/* GET_QUEUE_CLIENT ioctl() */
1754static int snd_seq_ioctl_get_queue_client(client_t * client, void __user *arg)
1755{
1756 snd_seq_queue_client_t info;
1757 int used;
1758
1759 if (copy_from_user(&info, arg, sizeof(info)))
1760 return -EFAULT;
1761
1762 used = snd_seq_queue_is_used(info.queue, client->number);
1763 if (used < 0)
1764 return -EINVAL;
1765 info.used = used;
1766 info.client = client->number;
1767
1768 if (copy_to_user(arg, &info, sizeof(info)))
1769 return -EFAULT;
1770 return 0;
1771}
1772
1773
1774/* SET_QUEUE_CLIENT ioctl() */
1775static int snd_seq_ioctl_set_queue_client(client_t * client, void __user *arg)
1776{
1777 int err;
1778 snd_seq_queue_client_t info;
1779
1780 if (copy_from_user(&info, arg, sizeof(info)))
1781 return -EFAULT;
1782
1783 if (info.used >= 0) {
1784 err = snd_seq_queue_use(info.queue, client->number, info.used);
1785 if (err < 0)
1786 return err;
1787 }
1788
1789 return snd_seq_ioctl_get_queue_client(client, arg);
1790}
1791
1792
1793/* GET_CLIENT_POOL ioctl() */
1794static int snd_seq_ioctl_get_client_pool(client_t * client, void __user *arg)
1795{
1796 snd_seq_client_pool_t info;
1797 client_t *cptr;
1798
1799 if (copy_from_user(&info, arg, sizeof(info)))
1800 return -EFAULT;
1801
1802 cptr = snd_seq_client_use_ptr(info.client);
1803 if (cptr == NULL)
1804 return -ENOENT;
1805 memset(&info, 0, sizeof(info));
1806 info.output_pool = cptr->pool->size;
1807 info.output_room = cptr->pool->room;
1808 info.output_free = info.output_pool;
1809 if (cptr->pool)
1810 info.output_free = snd_seq_unused_cells(cptr->pool);
1811 if (cptr->type == USER_CLIENT) {
1812 info.input_pool = cptr->data.user.fifo_pool_size;
1813 info.input_free = info.input_pool;
1814 if (cptr->data.user.fifo)
1815 info.input_free = snd_seq_unused_cells(cptr->data.user.fifo->pool);
1816 } else {
1817 info.input_pool = 0;
1818 info.input_free = 0;
1819 }
1820 snd_seq_client_unlock(cptr);
1821
1822 if (copy_to_user(arg, &info, sizeof(info)))
1823 return -EFAULT;
1824 return 0;
1825}
1826
1827/* SET_CLIENT_POOL ioctl() */
1828static int snd_seq_ioctl_set_client_pool(client_t * client, void __user *arg)
1829{
1830 snd_seq_client_pool_t info;
1831 int rc;
1832
1833 if (copy_from_user(&info, arg, sizeof(info)))
1834 return -EFAULT;
1835
1836 if (client->number != info.client)
1837 return -EINVAL; /* can't change other clients */
1838
1839 if (info.output_pool >= 1 && info.output_pool <= SNDRV_SEQ_MAX_EVENTS &&
1840 (! snd_seq_write_pool_allocated(client) ||
1841 info.output_pool != client->pool->size)) {
1842 if (snd_seq_write_pool_allocated(client)) {
1843 /* remove all existing cells */
1844 snd_seq_queue_client_leave_cells(client->number);
1845 snd_seq_pool_done(client->pool);
1846 }
1847 client->pool->size = info.output_pool;
1848 rc = snd_seq_pool_init(client->pool);
1849 if (rc < 0)
1850 return rc;
1851 }
1852 if (client->type == USER_CLIENT && client->data.user.fifo != NULL &&
1853 info.input_pool >= 1 &&
1854 info.input_pool <= SNDRV_SEQ_MAX_CLIENT_EVENTS &&
1855 info.input_pool != client->data.user.fifo_pool_size) {
1856 /* change pool size */
1857 rc = snd_seq_fifo_resize(client->data.user.fifo, info.input_pool);
1858 if (rc < 0)
1859 return rc;
1860 client->data.user.fifo_pool_size = info.input_pool;
1861 }
1862 if (info.output_room >= 1 &&
1863 info.output_room <= client->pool->size) {
1864 client->pool->room = info.output_room;
1865 }
1866
1867 return snd_seq_ioctl_get_client_pool(client, arg);
1868}
1869
1870
1871/* REMOVE_EVENTS ioctl() */
1872static int snd_seq_ioctl_remove_events(client_t * client, void __user *arg)
1873{
1874 snd_seq_remove_events_t info;
1875
1876 if (copy_from_user(&info, arg, sizeof(info)))
1877 return -EFAULT;
1878
1879 /*
1880 * Input mostly not implemented XXX.
1881 */
1882 if (info.remove_mode & SNDRV_SEQ_REMOVE_INPUT) {
1883 /*
1884 * No restrictions so for a user client we can clear
1885 * the whole fifo
1886 */
1887 if (client->type == USER_CLIENT)
1888 snd_seq_fifo_clear(client->data.user.fifo);
1889 }
1890
1891 if (info.remove_mode & SNDRV_SEQ_REMOVE_OUTPUT)
1892 snd_seq_queue_remove_cells(client->number, &info);
1893
1894 return 0;
1895}
1896
1897
1898/*
1899 * get subscription info
1900 */
1901static int snd_seq_ioctl_get_subscription(client_t *client, void __user *arg)
1902{
1903 int result;
1904 client_t *sender = NULL;
1905 client_port_t *sport = NULL;
1906 snd_seq_port_subscribe_t subs;
1907 subscribers_t *p;
1908
1909 if (copy_from_user(&subs, arg, sizeof(subs)))
1910 return -EFAULT;
1911
1912 result = -EINVAL;
1913 if ((sender = snd_seq_client_use_ptr(subs.sender.client)) == NULL)
1914 goto __end;
1915 if ((sport = snd_seq_port_use_ptr(sender, subs.sender.port)) == NULL)
1916 goto __end;
1917 p = snd_seq_port_get_subscription(&sport->c_src, &subs.dest);
1918 if (p) {
1919 result = 0;
1920 subs = p->info;
1921 } else
1922 result = -ENOENT;
1923
1924 __end:
1925 if (sport)
1926 snd_seq_port_unlock(sport);
1927 if (sender)
1928 snd_seq_client_unlock(sender);
1929 if (result >= 0) {
1930 if (copy_to_user(arg, &subs, sizeof(subs)))
1931 return -EFAULT;
1932 }
1933 return result;
1934}
1935
1936
1937/*
1938 * get subscription info - check only its presence
1939 */
1940static int snd_seq_ioctl_query_subs(client_t *client, void __user *arg)
1941{
1942 int result = -ENXIO;
1943 client_t *cptr = NULL;
1944 client_port_t *port = NULL;
1945 snd_seq_query_subs_t subs;
1946 port_subs_info_t *group;
1947 struct list_head *p;
1948 int i;
1949
1950 if (copy_from_user(&subs, arg, sizeof(subs)))
1951 return -EFAULT;
1952
1953 if ((cptr = snd_seq_client_use_ptr(subs.root.client)) == NULL)
1954 goto __end;
1955 if ((port = snd_seq_port_use_ptr(cptr, subs.root.port)) == NULL)
1956 goto __end;
1957
1958 switch (subs.type) {
1959 case SNDRV_SEQ_QUERY_SUBS_READ:
1960 group = &port->c_src;
1961 break;
1962 case SNDRV_SEQ_QUERY_SUBS_WRITE:
1963 group = &port->c_dest;
1964 break;
1965 default:
1966 goto __end;
1967 }
1968
1969 down_read(&group->list_mutex);
1970 /* search for the subscriber */
1971 subs.num_subs = group->count;
1972 i = 0;
1973 result = -ENOENT;
1974 list_for_each(p, &group->list_head) {
1975 if (i++ == subs.index) {
1976 /* found! */
1977 subscribers_t *s;
1978 if (subs.type == SNDRV_SEQ_QUERY_SUBS_READ) {
1979 s = list_entry(p, subscribers_t, src_list);
1980 subs.addr = s->info.dest;
1981 } else {
1982 s = list_entry(p, subscribers_t, dest_list);
1983 subs.addr = s->info.sender;
1984 }
1985 subs.flags = s->info.flags;
1986 subs.queue = s->info.queue;
1987 result = 0;
1988 break;
1989 }
1990 }
1991 up_read(&group->list_mutex);
1992
1993 __end:
1994 if (port)
1995 snd_seq_port_unlock(port);
1996 if (cptr)
1997 snd_seq_client_unlock(cptr);
1998 if (result >= 0) {
1999 if (copy_to_user(arg, &subs, sizeof(subs)))
2000 return -EFAULT;
2001 }
2002 return result;
2003}
2004
2005
2006/*
2007 * query next client
2008 */
2009static int snd_seq_ioctl_query_next_client(client_t *client, void __user *arg)
2010{
2011 client_t *cptr = NULL;
2012 snd_seq_client_info_t info;
2013
2014 if (copy_from_user(&info, arg, sizeof(info)))
2015 return -EFAULT;
2016
2017 /* search for next client */
2018 info.client++;
2019 if (info.client < 0)
2020 info.client = 0;
2021 for (; info.client < SNDRV_SEQ_MAX_CLIENTS; info.client++) {
2022 cptr = snd_seq_client_use_ptr(info.client);
2023 if (cptr)
2024 break; /* found */
2025 }
2026 if (cptr == NULL)
2027 return -ENOENT;
2028
2029 get_client_info(cptr, &info);
2030 snd_seq_client_unlock(cptr);
2031
2032 if (copy_to_user(arg, &info, sizeof(info)))
2033 return -EFAULT;
2034 return 0;
2035}
2036
2037/*
2038 * query next port
2039 */
2040static int snd_seq_ioctl_query_next_port(client_t *client, void __user *arg)
2041{
2042 client_t *cptr;
2043 client_port_t *port = NULL;
2044 snd_seq_port_info_t info;
2045
2046 if (copy_from_user(&info, arg, sizeof(info)))
2047 return -EFAULT;
2048 cptr = snd_seq_client_use_ptr(info.addr.client);
2049 if (cptr == NULL)
2050 return -ENXIO;
2051
2052 /* search for next port */
2053 info.addr.port++;
2054 port = snd_seq_port_query_nearest(cptr, &info);
2055 if (port == NULL) {
2056 snd_seq_client_unlock(cptr);
2057 return -ENOENT;
2058 }
2059
2060 /* get port info */
2061 info.addr = port->addr;
2062 snd_seq_get_port_info(port, &info);
2063 snd_seq_port_unlock(port);
2064 snd_seq_client_unlock(cptr);
2065
2066 if (copy_to_user(arg, &info, sizeof(info)))
2067 return -EFAULT;
2068 return 0;
2069}
2070
2071/* -------------------------------------------------------- */
2072
2073static struct seq_ioctl_table {
2074 unsigned int cmd;
2075 int (*func)(client_t *client, void __user * arg);
2076} ioctl_tables[] = {
2077 { SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
2078 { SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
2079 { SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info },
2080 { SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, snd_seq_ioctl_set_client_info },
2081 { SNDRV_SEQ_IOCTL_CREATE_PORT, snd_seq_ioctl_create_port },
2082 { SNDRV_SEQ_IOCTL_DELETE_PORT, snd_seq_ioctl_delete_port },
2083 { SNDRV_SEQ_IOCTL_GET_PORT_INFO, snd_seq_ioctl_get_port_info },
2084 { SNDRV_SEQ_IOCTL_SET_PORT_INFO, snd_seq_ioctl_set_port_info },
2085 { SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, snd_seq_ioctl_subscribe_port },
2086 { SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, snd_seq_ioctl_unsubscribe_port },
2087 { SNDRV_SEQ_IOCTL_CREATE_QUEUE, snd_seq_ioctl_create_queue },
2088 { SNDRV_SEQ_IOCTL_DELETE_QUEUE, snd_seq_ioctl_delete_queue },
2089 { SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, snd_seq_ioctl_get_queue_info },
2090 { SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, snd_seq_ioctl_set_queue_info },
2091 { SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, snd_seq_ioctl_get_named_queue },
2092 { SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, snd_seq_ioctl_get_queue_status },
2093 { SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, snd_seq_ioctl_get_queue_tempo },
2094 { SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, snd_seq_ioctl_set_queue_tempo },
2095 { SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, snd_seq_ioctl_get_queue_timer },
2096 { SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, snd_seq_ioctl_set_queue_timer },
2097 { SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, snd_seq_ioctl_get_queue_client },
2098 { SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, snd_seq_ioctl_set_queue_client },
2099 { SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, snd_seq_ioctl_get_client_pool },
2100 { SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, snd_seq_ioctl_set_client_pool },
2101 { SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, snd_seq_ioctl_get_subscription },
2102 { SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, snd_seq_ioctl_query_next_client },
2103 { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, snd_seq_ioctl_query_next_port },
2104 { SNDRV_SEQ_IOCTL_REMOVE_EVENTS, snd_seq_ioctl_remove_events },
2105 { SNDRV_SEQ_IOCTL_QUERY_SUBS, snd_seq_ioctl_query_subs },
2106 { 0, NULL },
2107};
2108
2109static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg)
2110{
2111 struct seq_ioctl_table *p;
2112
2113 switch (cmd) {
2114 case SNDRV_SEQ_IOCTL_PVERSION:
2115 /* return sequencer version number */
2116 return put_user(SNDRV_SEQ_VERSION, (int __user *)arg) ? -EFAULT : 0;
2117 case SNDRV_SEQ_IOCTL_CLIENT_ID:
2118 /* return the id of this client */
2119 return put_user(client->number, (int __user *)arg) ? -EFAULT : 0;
2120 }
2121
2122 if (! arg)
2123 return -EFAULT;
2124 for (p = ioctl_tables; p->cmd; p++) {
2125 if (p->cmd == cmd)
2126 return p->func(client, arg);
2127 }
2128 snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",
2129 cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
2130 return -ENOTTY;
2131}
2132
2133
2134static long snd_seq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
2135{
2136 client_t *client = (client_t *) file->private_data;
2137
2138 snd_assert(client != NULL, return -ENXIO);
2139
2140 return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
2141}
2142
2143#ifdef CONFIG_COMPAT
2144#include "seq_compat.c"
2145#else
2146#define snd_seq_ioctl_compat NULL
2147#endif
2148
2149/* -------------------------------------------------------- */
2150
2151
2152/* exported to kernel modules */
2153int snd_seq_create_kernel_client(snd_card_t *card, int client_index, snd_seq_client_callback_t * callback)
2154{
2155 client_t *client;
2156
2157 snd_assert(! in_interrupt(), return -EBUSY);
2158
2159 if (callback == NULL)
2160 return -EINVAL;
2161 if (card && client_index > 7)
2162 return -EINVAL;
2163 if (card == NULL && client_index > 63)
2164 return -EINVAL;
2165 if (card)
2166 client_index += 64 + (card->number << 3);
2167
2168 if (down_interruptible(&register_mutex))
2169 return -ERESTARTSYS;
2170 /* empty write queue as default */
2171 client = seq_create_client1(client_index, 0);
2172 if (client == NULL) {
2173 up(&register_mutex);
2174 return -EBUSY; /* failure code */
2175 }
2176 usage_alloc(&client_usage, 1);
2177
2178 client->accept_input = callback->allow_output;
2179 client->accept_output = callback->allow_input;
2180
2181 /* fill client data */
2182 client->data.kernel.card = card;
2183 client->data.kernel.private_data = callback->private_data;
2184 sprintf(client->name, "Client-%d", client->number);
2185
2186 client->type = KERNEL_CLIENT;
2187 up(&register_mutex);
2188
2189 /* make others aware this new client */
2190 snd_seq_system_client_ev_client_start(client->number);
2191
2192 /* return client number to caller */
2193 return client->number;
2194}
2195
2196/* exported to kernel modules */
2197int snd_seq_delete_kernel_client(int client)
2198{
2199 client_t *ptr;
2200
2201 snd_assert(! in_interrupt(), return -EBUSY);
2202
2203 ptr = clientptr(client);
2204 if (ptr == NULL)
2205 return -EINVAL;
2206
2207 seq_free_client(ptr);
2208 kfree(ptr);
2209 return 0;
2210}
2211
2212
2213/* skeleton to enqueue event, called from snd_seq_kernel_client_enqueue
2214 * and snd_seq_kernel_client_enqueue_blocking
2215 */
2216static int kernel_client_enqueue(int client, snd_seq_event_t *ev,
2217 struct file *file, int blocking,
2218 int atomic, int hop)
2219{
2220 client_t *cptr;
2221 int result;
2222
2223 snd_assert(ev != NULL, return -EINVAL);
2224
2225 if (ev->type == SNDRV_SEQ_EVENT_NONE)
2226 return 0; /* ignore this */
2227 if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
2228 return -EINVAL; /* quoted events can't be enqueued */
2229
2230 /* fill in client number */
2231 ev->source.client = client;
2232
2233 if (check_event_type_and_length(ev))
2234 return -EINVAL;
2235
2236 cptr = snd_seq_client_use_ptr(client);
2237 if (cptr == NULL)
2238 return -EINVAL;
2239
2240 if (! cptr->accept_output)
2241 result = -EPERM;
2242 else /* send it */
2243 result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop);
2244
2245 snd_seq_client_unlock(cptr);
2246 return result;
2247}
2248
2249/*
2250 * exported, called by kernel clients to enqueue events (w/o blocking)
2251 *
2252 * RETURN VALUE: zero if succeed, negative if error
2253 */
2254int snd_seq_kernel_client_enqueue(int client, snd_seq_event_t * ev,
2255 int atomic, int hop)
2256{
2257 return kernel_client_enqueue(client, ev, NULL, 0, atomic, hop);
2258}
2259
2260/*
2261 * exported, called by kernel clients to enqueue events (with blocking)
2262 *
2263 * RETURN VALUE: zero if succeed, negative if error
2264 */
2265int snd_seq_kernel_client_enqueue_blocking(int client, snd_seq_event_t * ev,
2266 struct file *file,
2267 int atomic, int hop)
2268{
2269 return kernel_client_enqueue(client, ev, file, 1, atomic, hop);
2270}
2271
2272
2273/*
2274 * exported, called by kernel clients to dispatch events directly to other
2275 * clients, bypassing the queues. Event time-stamp will be updated.
2276 *
2277 * RETURN VALUE: negative = delivery failed,
2278 * zero, or positive: the number of delivered events
2279 */
2280int snd_seq_kernel_client_dispatch(int client, snd_seq_event_t * ev,
2281 int atomic, int hop)
2282{
2283 client_t *cptr;
2284 int result;
2285
2286 snd_assert(ev != NULL, return -EINVAL);
2287
2288 /* fill in client number */
2289 ev->queue = SNDRV_SEQ_QUEUE_DIRECT;
2290 ev->source.client = client;
2291
2292 if (check_event_type_and_length(ev))
2293 return -EINVAL;
2294
2295 cptr = snd_seq_client_use_ptr(client);
2296 if (cptr == NULL)
2297 return -EINVAL;
2298
2299 if (!cptr->accept_output)
2300 result = -EPERM;
2301 else
2302 result = snd_seq_deliver_event(cptr, ev, atomic, hop);
2303
2304 snd_seq_client_unlock(cptr);
2305 return result;
2306}
2307
2308
2309/*
2310 * exported, called by kernel clients to perform same functions as with
2311 * userland ioctl()
2312 */
2313int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
2314{
2315 client_t *client;
2316 mm_segment_t fs;
2317 int result;
2318
2319 client = clientptr(clientid);
2320 if (client == NULL)
2321 return -ENXIO;
2322 fs = snd_enter_user();
2323 result = snd_seq_do_ioctl(client, cmd, (void __user *)arg);
2324 snd_leave_user(fs);
2325 return result;
2326}
2327
2328
2329/* exported (for OSS emulator) */
2330int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait)
2331{
2332 client_t *client;
2333
2334 client = clientptr(clientid);
2335 if (client == NULL)
2336 return -ENXIO;
2337
2338 if (! snd_seq_write_pool_allocated(client))
2339 return 1;
2340 if (snd_seq_pool_poll_wait(client->pool, file, wait))
2341 return 1;
2342 return 0;
2343}
2344
2345/*---------------------------------------------------------------------------*/
2346
2347/*
2348 * /proc interface
2349 */
2350static void snd_seq_info_dump_subscribers(snd_info_buffer_t *buffer, port_subs_info_t *group, int is_src, char *msg)
2351{
2352 struct list_head *p;
2353 subscribers_t *s;
2354 int count = 0;
2355
2356 down_read(&group->list_mutex);
2357 if (list_empty(&group->list_head)) {
2358 up_read(&group->list_mutex);
2359 return;
2360 }
2361 snd_iprintf(buffer, msg);
2362 list_for_each(p, &group->list_head) {
2363 if (is_src)
2364 s = list_entry(p, subscribers_t, src_list);
2365 else
2366 s = list_entry(p, subscribers_t, dest_list);
2367 if (count++)
2368 snd_iprintf(buffer, ", ");
2369 snd_iprintf(buffer, "%d:%d",
2370 is_src ? s->info.dest.client : s->info.sender.client,
2371 is_src ? s->info.dest.port : s->info.sender.port);
2372 if (s->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
2373 snd_iprintf(buffer, "[%c:%d]", ((s->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) ? 'r' : 't'), s->info.queue);
2374 if (group->exclusive)
2375 snd_iprintf(buffer, "[ex]");
2376 }
2377 up_read(&group->list_mutex);
2378 snd_iprintf(buffer, "\n");
2379}
2380
2381#define FLAG_PERM_RD(perm) ((perm) & SNDRV_SEQ_PORT_CAP_READ ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_READ ? 'R' : 'r') : '-')
2382#define FLAG_PERM_WR(perm) ((perm) & SNDRV_SEQ_PORT_CAP_WRITE ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_WRITE ? 'W' : 'w') : '-')
2383#define FLAG_PERM_EX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_NO_EXPORT ? '-' : 'e')
2384
2385#define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')
2386
2387static void snd_seq_info_dump_ports(snd_info_buffer_t *buffer, client_t *client)
2388{
2389 struct list_head *l;
2390
2391 down(&client->ports_mutex);
2392 list_for_each(l, &client->ports_list_head) {
2393 client_port_t *p = list_entry(l, client_port_t, list);
2394 snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
2395 p->addr.port, p->name,
2396 FLAG_PERM_RD(p->capability),
2397 FLAG_PERM_WR(p->capability),
2398 FLAG_PERM_EX(p->capability),
2399 FLAG_PERM_DUPLEX(p->capability));
2400 snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: ");
2401 snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: ");
2402 }
2403 up(&client->ports_mutex);
2404}
2405
2406
2407/* exported to seq_info.c */
2408void snd_seq_info_clients_read(snd_info_entry_t *entry,
2409 snd_info_buffer_t * buffer)
2410{
2411 extern void snd_seq_info_pool(snd_info_buffer_t * buffer, pool_t * pool, char *space);
2412 int c;
2413 client_t *client;
2414
2415 snd_iprintf(buffer, "Client info\n");
2416 snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur);
2417 snd_iprintf(buffer, " peak clients : %d\n", client_usage.peak);
2418 snd_iprintf(buffer, " max clients : %d\n", SNDRV_SEQ_MAX_CLIENTS);
2419 snd_iprintf(buffer, "\n");
2420
2421 /* list the client table */
2422 for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
2423 client = snd_seq_client_use_ptr(c);
2424 if (client == NULL)
2425 continue;
2426 if (client->type == NO_CLIENT) {
2427 snd_seq_client_unlock(client);
2428 continue;
2429 }
2430
2431 snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n",
2432 c, client->name,
2433 client->type == USER_CLIENT ? "User" : "Kernel");
2434 snd_seq_info_dump_ports(buffer, client);
2435 if (snd_seq_write_pool_allocated(client)) {
2436 snd_iprintf(buffer, " Output pool :\n");
2437 snd_seq_info_pool(buffer, client->pool, " ");
2438 }
2439 if (client->type == USER_CLIENT && client->data.user.fifo &&
2440 client->data.user.fifo->pool) {
2441 snd_iprintf(buffer, " Input pool :\n");
2442 snd_seq_info_pool(buffer, client->data.user.fifo->pool, " ");
2443 }
2444 snd_seq_client_unlock(client);
2445 }
2446}
2447
2448
2449/*---------------------------------------------------------------------------*/
2450
2451
2452/*
2453 * REGISTRATION PART
2454 */
2455
2456static struct file_operations snd_seq_f_ops =
2457{
2458 .owner = THIS_MODULE,
2459 .read = snd_seq_read,
2460 .write = snd_seq_write,
2461 .open = snd_seq_open,
2462 .release = snd_seq_release,
2463 .poll = snd_seq_poll,
2464 .unlocked_ioctl = snd_seq_ioctl,
2465 .compat_ioctl = snd_seq_ioctl_compat,
2466};
2467
2468static snd_minor_t snd_seq_reg =
2469{
2470 .comment = "sequencer",
2471 .f_ops = &snd_seq_f_ops,
2472};
2473
2474
2475/*
2476 * register sequencer device
2477 */
2478int __init snd_sequencer_device_init(void)
2479{
2480 int err;
2481
2482 if (down_interruptible(&register_mutex))
2483 return -ERESTARTSYS;
2484
2485 if ((err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0, &snd_seq_reg, "seq")) < 0) {
2486 up(&register_mutex);
2487 return err;
2488 }
2489
2490 up(&register_mutex);
2491
2492 return 0;
2493}
2494
2495
2496
2497/*
2498 * unregister sequencer device
2499 */
2500void __exit snd_sequencer_device_done(void)
2501{
2502 snd_unregister_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0);
2503}
diff --git a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h
new file mode 100644
index 000000000000..3715c36183d3
--- /dev/null
+++ b/sound/core/seq/seq_clientmgr.h
@@ -0,0 +1,104 @@
1/*
2 * ALSA sequencer Client Manager
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_CLIENTMGR_H
22#define __SND_SEQ_CLIENTMGR_H
23
24#include <sound/seq_kernel.h>
25#include <linux/bitops.h>
26#include "seq_fifo.h"
27#include "seq_ports.h"
28#include "seq_lock.h"
29
30
31/* client manager */
32
33struct _snd_seq_user_client {
34 struct file *file; /* file struct of client */
35 /* ... */
36
37 /* fifo */
38 fifo_t *fifo; /* queue for incoming events */
39 int fifo_pool_size;
40};
41
42struct _snd_seq_kernel_client {
43 snd_card_t *card;
44 /* pointer to client functions */
45 void *private_data; /* private data for client */
46 /* ... */
47};
48
49
50struct _snd_seq_client {
51 snd_seq_client_type_t type;
52 unsigned int accept_input: 1,
53 accept_output: 1;
54 char name[64]; /* client name */
55 int number; /* client number */
56 unsigned int filter; /* filter flags */
57 DECLARE_BITMAP(event_filter, 256);
58 snd_use_lock_t use_lock;
59 int event_lost;
60 /* ports */
61 int num_ports; /* number of ports */
62 struct list_head ports_list_head;
63 rwlock_t ports_lock;
64 struct semaphore ports_mutex;
65 int convert32; /* convert 32->64bit */
66
67 /* output pool */
68 pool_t *pool; /* memory pool for this client */
69
70 union {
71 user_client_t user;
72 kernel_client_t kernel;
73 } data;
74};
75
76/* usage statistics */
77typedef struct {
78 int cur;
79 int peak;
80} usage_t;
81
82
83extern int client_init_data(void);
84extern int snd_sequencer_device_init(void);
85extern void snd_sequencer_device_done(void);
86
87/* get locked pointer to client */
88extern client_t *snd_seq_client_use_ptr(int clientid);
89
90/* unlock pointer to client */
91#define snd_seq_client_unlock(client) snd_use_lock_free(&(client)->use_lock)
92
93/* dispatch event to client(s) */
94extern int snd_seq_dispatch_event(snd_seq_event_cell_t *cell, int atomic, int hop);
95
96/* exported to other modules */
97extern int snd_seq_register_kernel_client(snd_seq_client_callback_t *callback, void *private_data);
98extern int snd_seq_unregister_kernel_client(int client);
99extern int snd_seq_kernel_client_enqueue(int client, snd_seq_event_t *ev, int atomic, int hop);
100int snd_seq_kernel_client_enqueue_blocking(int client, snd_seq_event_t * ev, struct file *file, int atomic, int hop);
101int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait);
102int snd_seq_client_notify_subscription(int client, int port, snd_seq_port_subscribe_t *info, int evtype);
103
104#endif
diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c
new file mode 100644
index 000000000000..902ad8b0c355
--- /dev/null
+++ b/sound/core/seq/seq_compat.c
@@ -0,0 +1,137 @@
1/*
2 * 32bit -> 64bit ioctl wrapper for sequencer API
3 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21/* This file included from seq.c */
22
23#include <linux/compat.h>
24
25struct sndrv_seq_port_info32 {
26 struct sndrv_seq_addr addr; /* client/port numbers */
27 char name[64]; /* port name */
28
29 u32 capability; /* port capability bits */
30 u32 type; /* port type bits */
31 s32 midi_channels; /* channels per MIDI port */
32 s32 midi_voices; /* voices per MIDI port */
33 s32 synth_voices; /* voices per SYNTH port */
34
35 s32 read_use; /* R/O: subscribers for output (from this port) */
36 s32 write_use; /* R/O: subscribers for input (to this port) */
37
38 u32 kernel; /* reserved for kernel use (must be NULL) */
39 u32 flags; /* misc. conditioning */
40 unsigned char time_queue; /* queue # for timestamping */
41 char reserved[59]; /* for future use */
42};
43
44static int snd_seq_call_port_info_ioctl(client_t *client, unsigned int cmd,
45 struct sndrv_seq_port_info32 __user *data32)
46{
47 int err = -EFAULT;
48 snd_seq_port_info_t *data;
49 mm_segment_t fs;
50
51 data = kmalloc(sizeof(*data), GFP_KERNEL);
52 if (! data)
53 return -ENOMEM;
54
55 if (copy_from_user(data, data32, sizeof(*data32)) ||
56 get_user(data->flags, &data32->flags) ||
57 get_user(data->time_queue, &data32->time_queue))
58 goto error;
59 data->kernel = NULL;
60
61 fs = snd_enter_user();
62 err = snd_seq_do_ioctl(client, cmd, data);
63 snd_leave_user(fs);
64 if (err < 0)
65 goto error;
66
67 if (copy_to_user(data32, data, sizeof(*data32)) ||
68 put_user(data->flags, &data32->flags) ||
69 put_user(data->time_queue, &data32->time_queue))
70 err = -EFAULT;
71
72 error:
73 kfree(data);
74 return err;
75}
76
77
78
79/*
80 */
81
82enum {
83 SNDRV_SEQ_IOCTL_CREATE_PORT32 = _IOWR('S', 0x20, struct sndrv_seq_port_info32),
84 SNDRV_SEQ_IOCTL_DELETE_PORT32 = _IOW ('S', 0x21, struct sndrv_seq_port_info32),
85 SNDRV_SEQ_IOCTL_GET_PORT_INFO32 = _IOWR('S', 0x22, struct sndrv_seq_port_info32),
86 SNDRV_SEQ_IOCTL_SET_PORT_INFO32 = _IOW ('S', 0x23, struct sndrv_seq_port_info32),
87 SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32 = _IOWR('S', 0x52, struct sndrv_seq_port_info32),
88};
89
90static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
91{
92 client_t *client = (client_t *) file->private_data;
93 void __user *argp = compat_ptr(arg);
94
95 snd_assert(client != NULL, return -ENXIO);
96
97 switch (cmd) {
98 case SNDRV_SEQ_IOCTL_PVERSION:
99 case SNDRV_SEQ_IOCTL_CLIENT_ID:
100 case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
101 case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
102 case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
103 case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
104 case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
105 case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
106 case SNDRV_SEQ_IOCTL_DELETE_QUEUE:
107 case SNDRV_SEQ_IOCTL_GET_QUEUE_INFO:
108 case SNDRV_SEQ_IOCTL_SET_QUEUE_INFO:
109 case SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE:
110 case SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS:
111 case SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO:
112 case SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO:
113 case SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER:
114 case SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER:
115 case SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT:
116 case SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT:
117 case SNDRV_SEQ_IOCTL_GET_CLIENT_POOL:
118 case SNDRV_SEQ_IOCTL_SET_CLIENT_POOL:
119 case SNDRV_SEQ_IOCTL_REMOVE_EVENTS:
120 case SNDRV_SEQ_IOCTL_QUERY_SUBS:
121 case SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION:
122 case SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT:
123 case SNDRV_SEQ_IOCTL_RUNNING_MODE:
124 return snd_seq_do_ioctl(client, cmd, argp);
125 case SNDRV_SEQ_IOCTL_CREATE_PORT32:
126 return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, argp);
127 case SNDRV_SEQ_IOCTL_DELETE_PORT32:
128 return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_DELETE_PORT, argp);
129 case SNDRV_SEQ_IOCTL_GET_PORT_INFO32:
130 return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_GET_PORT_INFO, argp);
131 case SNDRV_SEQ_IOCTL_SET_PORT_INFO32:
132 return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_SET_PORT_INFO, argp);
133 case SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT32:
134 return snd_seq_call_port_info_ioctl(client, SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, argp);
135 }
136 return -ENOIOCTLCMD;
137}
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
new file mode 100644
index 000000000000..4d80f39612e8
--- /dev/null
+++ b/sound/core/seq/seq_device.c
@@ -0,0 +1,575 @@
1/*
2 * ALSA sequencer device management
3 * Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 *
20 *----------------------------------------------------------------
21 *
22 * This device handler separates the card driver module from sequencer
23 * stuff (sequencer core, synth drivers, etc), so that user can avoid
24 * to spend unnecessary resources e.g. if he needs only listening to
25 * MP3s.
26 *
27 * The card (or lowlevel) driver creates a sequencer device entry
28 * via snd_seq_device_new(). This is an entry pointer to communicate
29 * with the sequencer device "driver", which is involved with the
30 * actual part to communicate with the sequencer core.
31 * Each sequencer device entry has an id string and the corresponding
32 * driver with the same id is loaded when required. For example,
33 * lowlevel codes to access emu8000 chip on sbawe card are included in
34 * emu8000-synth module. To activate this module, the hardware
35 * resources like i/o port are passed via snd_seq_device argument.
36 *
37 */
38
39#include <sound/driver.h>
40#include <linux/init.h>
41#include <sound/core.h>
42#include <sound/info.h>
43#include <sound/seq_device.h>
44#include <sound/seq_kernel.h>
45#include <sound/initval.h>
46#include <linux/kmod.h>
47#include <linux/slab.h>
48
49MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
50MODULE_DESCRIPTION("ALSA sequencer device management");
51MODULE_LICENSE("GPL");
52
53/*
54 * driver list
55 */
56typedef struct ops_list ops_list_t;
57
58/* driver state */
59#define DRIVER_EMPTY 0
60#define DRIVER_LOADED (1<<0)
61#define DRIVER_REQUESTED (1<<1)
62#define DRIVER_LOCKED (1<<2)
63
64struct ops_list {
65 char id[ID_LEN]; /* driver id */
66 int driver; /* driver state */
67 int used; /* reference counter */
68 int argsize; /* argument size */
69
70 /* operators */
71 snd_seq_dev_ops_t ops;
72
73 /* registred devices */
74 struct list_head dev_list; /* list of devices */
75 int num_devices; /* number of associated devices */
76 int num_init_devices; /* number of initialized devices */
77 struct semaphore reg_mutex;
78
79 struct list_head list; /* next driver */
80};
81
82
83static LIST_HEAD(opslist);
84static int num_ops;
85static DECLARE_MUTEX(ops_mutex);
86static snd_info_entry_t *info_entry = NULL;
87
88/*
89 * prototypes
90 */
91static int snd_seq_device_free(snd_seq_device_t *dev);
92static int snd_seq_device_dev_free(snd_device_t *device);
93static int snd_seq_device_dev_register(snd_device_t *device);
94static int snd_seq_device_dev_disconnect(snd_device_t *device);
95static int snd_seq_device_dev_unregister(snd_device_t *device);
96
97static int init_device(snd_seq_device_t *dev, ops_list_t *ops);
98static int free_device(snd_seq_device_t *dev, ops_list_t *ops);
99static ops_list_t *find_driver(char *id, int create_if_empty);
100static ops_list_t *create_driver(char *id);
101static void unlock_driver(ops_list_t *ops);
102static void remove_drivers(void);
103
104/*
105 * show all drivers and their status
106 */
107
108static void snd_seq_device_info(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
109{
110 struct list_head *head;
111
112 down(&ops_mutex);
113 list_for_each(head, &opslist) {
114 ops_list_t *ops = list_entry(head, ops_list_t, list);
115 snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
116 ops->id,
117 ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
118 ops->driver & DRIVER_REQUESTED ? ",requested" : "",
119 ops->driver & DRIVER_LOCKED ? ",locked" : "",
120 ops->num_devices);
121 }
122 up(&ops_mutex);
123}
124
125/*
126 * load all registered drivers (called from seq_clientmgr.c)
127 */
128
129#ifdef CONFIG_KMOD
130/* avoid auto-loading during module_init() */
131static int snd_seq_in_init;
132void snd_seq_autoload_lock(void)
133{
134 snd_seq_in_init++;
135}
136
137void snd_seq_autoload_unlock(void)
138{
139 snd_seq_in_init--;
140}
141#endif
142
143void snd_seq_device_load_drivers(void)
144{
145#ifdef CONFIG_KMOD
146 struct list_head *head;
147
148 /* Calling request_module during module_init()
149 * may cause blocking.
150 */
151 if (snd_seq_in_init)
152 return;
153
154 if (! current->fs->root)
155 return;
156
157 down(&ops_mutex);
158 list_for_each(head, &opslist) {
159 ops_list_t *ops = list_entry(head, ops_list_t, list);
160 if (! (ops->driver & DRIVER_LOADED) &&
161 ! (ops->driver & DRIVER_REQUESTED)) {
162 ops->used++;
163 up(&ops_mutex);
164 ops->driver |= DRIVER_REQUESTED;
165 request_module("snd-%s", ops->id);
166 down(&ops_mutex);
167 ops->used--;
168 }
169 }
170 up(&ops_mutex);
171#endif
172}
173
174/*
175 * register a sequencer device
176 * card = card info (NULL allowed)
177 * device = device number (if any)
178 * id = id of driver
179 * result = return pointer (NULL allowed if unnecessary)
180 */
181int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize,
182 snd_seq_device_t **result)
183{
184 snd_seq_device_t *dev;
185 ops_list_t *ops;
186 int err;
187 static snd_device_ops_t dops = {
188 .dev_free = snd_seq_device_dev_free,
189 .dev_register = snd_seq_device_dev_register,
190 .dev_disconnect = snd_seq_device_dev_disconnect,
191 .dev_unregister = snd_seq_device_dev_unregister
192 };
193
194 if (result)
195 *result = NULL;
196
197 snd_assert(id != NULL, return -EINVAL);
198
199 ops = find_driver(id, 1);
200 if (ops == NULL)
201 return -ENOMEM;
202
203 dev = kcalloc(1, sizeof(*dev)*2 + argsize, GFP_KERNEL);
204 if (dev == NULL) {
205 unlock_driver(ops);
206 return -ENOMEM;
207 }
208
209 /* set up device info */
210 dev->card = card;
211 dev->device = device;
212 strlcpy(dev->id, id, sizeof(dev->id));
213 dev->argsize = argsize;
214 dev->status = SNDRV_SEQ_DEVICE_FREE;
215
216 /* add this device to the list */
217 down(&ops->reg_mutex);
218 list_add_tail(&dev->list, &ops->dev_list);
219 ops->num_devices++;
220 up(&ops->reg_mutex);
221
222 unlock_driver(ops);
223
224 if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
225 snd_seq_device_free(dev);
226 return err;
227 }
228
229 if (result)
230 *result = dev;
231
232 return 0;
233}
234
235/*
236 * free the existing device
237 */
238static int snd_seq_device_free(snd_seq_device_t *dev)
239{
240 ops_list_t *ops;
241
242 snd_assert(dev != NULL, return -EINVAL);
243
244 ops = find_driver(dev->id, 0);
245 if (ops == NULL)
246 return -ENXIO;
247
248 /* remove the device from the list */
249 down(&ops->reg_mutex);
250 list_del(&dev->list);
251 ops->num_devices--;
252 up(&ops->reg_mutex);
253
254 free_device(dev, ops);
255 if (dev->private_free)
256 dev->private_free(dev);
257 kfree(dev);
258
259 unlock_driver(ops);
260
261 return 0;
262}
263
264static int snd_seq_device_dev_free(snd_device_t *device)
265{
266 snd_seq_device_t *dev = device->device_data;
267 return snd_seq_device_free(dev);
268}
269
270/*
271 * register the device
272 */
273static int snd_seq_device_dev_register(snd_device_t *device)
274{
275 snd_seq_device_t *dev = device->device_data;
276 ops_list_t *ops;
277
278 ops = find_driver(dev->id, 0);
279 if (ops == NULL)
280 return -ENOENT;
281
282 /* initialize this device if the corresponding driver was
283 * already loaded
284 */
285 if (ops->driver & DRIVER_LOADED)
286 init_device(dev, ops);
287
288 unlock_driver(ops);
289 return 0;
290}
291
292/*
293 * disconnect the device
294 */
295static int snd_seq_device_dev_disconnect(snd_device_t *device)
296{
297 snd_seq_device_t *dev = device->device_data;
298 ops_list_t *ops;
299
300 ops = find_driver(dev->id, 0);
301 if (ops == NULL)
302 return -ENOENT;
303
304 free_device(dev, ops);
305
306 unlock_driver(ops);
307 return 0;
308}
309
310/*
311 * unregister the existing device
312 */
313static int snd_seq_device_dev_unregister(snd_device_t *device)
314{
315 snd_seq_device_t *dev = device->device_data;
316 return snd_seq_device_free(dev);
317}
318
319/*
320 * register device driver
321 * id = driver id
322 * entry = driver operators - duplicated to each instance
323 */
324int snd_seq_device_register_driver(char *id, snd_seq_dev_ops_t *entry, int argsize)
325{
326 struct list_head *head;
327 ops_list_t *ops;
328
329 if (id == NULL || entry == NULL ||
330 entry->init_device == NULL || entry->free_device == NULL)
331 return -EINVAL;
332
333 snd_seq_autoload_lock();
334 ops = find_driver(id, 1);
335 if (ops == NULL) {
336 snd_seq_autoload_unlock();
337 return -ENOMEM;
338 }
339 if (ops->driver & DRIVER_LOADED) {
340 snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);
341 unlock_driver(ops);
342 snd_seq_autoload_unlock();
343 return -EBUSY;
344 }
345
346 down(&ops->reg_mutex);
347 /* copy driver operators */
348 ops->ops = *entry;
349 ops->driver |= DRIVER_LOADED;
350 ops->argsize = argsize;
351
352 /* initialize existing devices if necessary */
353 list_for_each(head, &ops->dev_list) {
354 snd_seq_device_t *dev = list_entry(head, snd_seq_device_t, list);
355 init_device(dev, ops);
356 }
357 up(&ops->reg_mutex);
358
359 unlock_driver(ops);
360 snd_seq_autoload_unlock();
361
362 return 0;
363}
364
365
366/*
367 * create driver record
368 */
369static ops_list_t * create_driver(char *id)
370{
371 ops_list_t *ops;
372
373 ops = kmalloc(sizeof(*ops), GFP_KERNEL);
374 if (ops == NULL)
375 return ops;
376 memset(ops, 0, sizeof(*ops));
377
378 /* set up driver entry */
379 strlcpy(ops->id, id, sizeof(ops->id));
380 init_MUTEX(&ops->reg_mutex);
381 ops->driver = DRIVER_EMPTY;
382 INIT_LIST_HEAD(&ops->dev_list);
383 /* lock this instance */
384 ops->used = 1;
385
386 /* register driver entry */
387 down(&ops_mutex);
388 list_add_tail(&ops->list, &opslist);
389 num_ops++;
390 up(&ops_mutex);
391
392 return ops;
393}
394
395
396/*
397 * unregister the specified driver
398 */
399int snd_seq_device_unregister_driver(char *id)
400{
401 struct list_head *head;
402 ops_list_t *ops;
403
404 ops = find_driver(id, 0);
405 if (ops == NULL)
406 return -ENXIO;
407 if (! (ops->driver & DRIVER_LOADED) ||
408 (ops->driver & DRIVER_LOCKED)) {
409 snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n", id, ops->driver);
410 unlock_driver(ops);
411 return -EBUSY;
412 }
413
414 /* close and release all devices associated with this driver */
415 down(&ops->reg_mutex);
416 ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
417 list_for_each(head, &ops->dev_list) {
418 snd_seq_device_t *dev = list_entry(head, snd_seq_device_t, list);
419 free_device(dev, ops);
420 }
421
422 ops->driver = 0;
423 if (ops->num_init_devices > 0)
424 snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n", ops->num_init_devices);
425 up(&ops->reg_mutex);
426
427 unlock_driver(ops);
428
429 /* remove empty driver entries */
430 remove_drivers();
431
432 return 0;
433}
434
435
436/*
437 * remove empty driver entries
438 */
439static void remove_drivers(void)
440{
441 struct list_head *head;
442
443 down(&ops_mutex);
444 head = opslist.next;
445 while (head != &opslist) {
446 ops_list_t *ops = list_entry(head, ops_list_t, list);
447 if (! (ops->driver & DRIVER_LOADED) &&
448 ops->used == 0 && ops->num_devices == 0) {
449 head = head->next;
450 list_del(&ops->list);
451 kfree(ops);
452 num_ops--;
453 } else
454 head = head->next;
455 }
456 up(&ops_mutex);
457}
458
459/*
460 * initialize the device - call init_device operator
461 */
462static int init_device(snd_seq_device_t *dev, ops_list_t *ops)
463{
464 if (! (ops->driver & DRIVER_LOADED))
465 return 0; /* driver is not loaded yet */
466 if (dev->status != SNDRV_SEQ_DEVICE_FREE)
467 return 0; /* already initialized */
468 if (ops->argsize != dev->argsize) {
469 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", dev->name, ops->id, ops->argsize, dev->argsize);
470 return -EINVAL;
471 }
472 if (ops->ops.init_device(dev) >= 0) {
473 dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
474 ops->num_init_devices++;
475 } else {
476 snd_printk(KERN_ERR "init_device failed: %s: %s\n", dev->name, dev->id);
477 }
478
479 return 0;
480}
481
482/*
483 * release the device - call free_device operator
484 */
485static int free_device(snd_seq_device_t *dev, ops_list_t *ops)
486{
487 int result;
488
489 if (! (ops->driver & DRIVER_LOADED))
490 return 0; /* driver is not loaded yet */
491 if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
492 return 0; /* not registered */
493 if (ops->argsize != dev->argsize) {
494 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", dev->name, ops->id, ops->argsize, dev->argsize);
495 return -EINVAL;
496 }
497 if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
498 dev->status = SNDRV_SEQ_DEVICE_FREE;
499 dev->driver_data = NULL;
500 ops->num_init_devices--;
501 } else {
502 snd_printk(KERN_ERR "free_device failed: %s: %s\n", dev->name, dev->id);
503 }
504
505 return 0;
506}
507
508/*
509 * find the matching driver with given id
510 */
511static ops_list_t * find_driver(char *id, int create_if_empty)
512{
513 struct list_head *head;
514
515 down(&ops_mutex);
516 list_for_each(head, &opslist) {
517 ops_list_t *ops = list_entry(head, ops_list_t, list);
518 if (strcmp(ops->id, id) == 0) {
519 ops->used++;
520 up(&ops_mutex);
521 return ops;
522 }
523 }
524 up(&ops_mutex);
525 if (create_if_empty)
526 return create_driver(id);
527 return NULL;
528}
529
530static void unlock_driver(ops_list_t *ops)
531{
532 down(&ops_mutex);
533 ops->used--;
534 up(&ops_mutex);
535}
536
537
538/*
539 * module part
540 */
541
542static int __init alsa_seq_device_init(void)
543{
544 info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", snd_seq_root);
545 if (info_entry == NULL)
546 return -ENOMEM;
547 info_entry->content = SNDRV_INFO_CONTENT_TEXT;
548 info_entry->c.text.read_size = 2048;
549 info_entry->c.text.read = snd_seq_device_info;
550 if (snd_info_register(info_entry) < 0) {
551 snd_info_free_entry(info_entry);
552 return -ENOMEM;
553 }
554 return 0;
555}
556
557static void __exit alsa_seq_device_exit(void)
558{
559 remove_drivers();
560 snd_info_unregister(info_entry);
561 if (num_ops)
562 snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
563}
564
565module_init(alsa_seq_device_init)
566module_exit(alsa_seq_device_exit)
567
568EXPORT_SYMBOL(snd_seq_device_load_drivers);
569EXPORT_SYMBOL(snd_seq_device_new);
570EXPORT_SYMBOL(snd_seq_device_register_driver);
571EXPORT_SYMBOL(snd_seq_device_unregister_driver);
572#ifdef CONFIG_KMOD
573EXPORT_SYMBOL(snd_seq_autoload_lock);
574EXPORT_SYMBOL(snd_seq_autoload_unlock);
575#endif
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c
new file mode 100644
index 000000000000..e88967c5b93d
--- /dev/null
+++ b/sound/core/seq/seq_dummy.c
@@ -0,0 +1,273 @@
1/*
2 * ALSA sequencer MIDI-through client
3 * Copyright (c) 1999-2000 by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/moduleparam.h>
25#include <sound/core.h>
26#include "seq_clientmgr.h"
27#include <sound/initval.h>
28#include <sound/asoundef.h>
29
30/*
31
32 Sequencer MIDI-through client
33
34 This gives a simple midi-through client. All the normal input events
35 are redirected to output port immediately.
36 The routing can be done via aconnect program in alsa-utils.
37
38 Each client has a static client number 62 (= SNDRV_SEQ_CLIENT_DUMMY).
39 If you want to auto-load this module, you may add the following alias
40 in your /etc/conf.modules file.
41
42 alias snd-seq-client-62 snd-seq-dummy
43
44 The module is loaded on demand for client 62, or /proc/asound/seq/
45 is accessed. If you don't need this module to be loaded, alias
46 snd-seq-client-62 as "off". This will help modprobe.
47
48 The number of ports to be created can be specified via the module
49 parameter "ports". For example, to create four ports, add the
50 following option in /etc/modprobe.conf:
51
52 option snd-seq-dummy ports=4
53
54 The modle option "duplex=1" enables duplex operation to the port.
55 In duplex mode, a pair of ports are created instead of single port,
56 and events are tunneled between pair-ports. For example, input to
57 port A is sent to output port of another port B and vice versa.
58 In duplex mode, each port has DUPLEX capability.
59
60 */
61
62
63MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
64MODULE_DESCRIPTION("ALSA sequencer MIDI-through client");
65MODULE_LICENSE("GPL");
66MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY));
67
68static int ports = 1;
69static int duplex = 0;
70
71module_param(ports, int, 0444);
72MODULE_PARM_DESC(ports, "number of ports to be created");
73module_param(duplex, bool, 0444);
74MODULE_PARM_DESC(duplex, "create DUPLEX ports");
75
76typedef struct snd_seq_dummy_port {
77 int client;
78 int port;
79 int duplex;
80 int connect;
81} snd_seq_dummy_port_t;
82
83static int my_client = -1;
84
85/*
86 * unuse callback - send ALL_SOUNDS_OFF and RESET_CONTROLLERS events
87 * to subscribers.
88 * Note: this callback is called only after all subscribers are removed.
89 */
90static int
91dummy_unuse(void *private_data, snd_seq_port_subscribe_t *info)
92{
93 snd_seq_dummy_port_t *p;
94 int i;
95 snd_seq_event_t ev;
96
97 p = private_data;
98 memset(&ev, 0, sizeof(ev));
99 if (p->duplex)
100 ev.source.port = p->connect;
101 else
102 ev.source.port = p->port;
103 ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
104 ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
105 for (i = 0; i < 16; i++) {
106 ev.data.control.channel = i;
107 ev.data.control.param = MIDI_CTL_ALL_SOUNDS_OFF;
108 snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0);
109 ev.data.control.param = MIDI_CTL_RESET_CONTROLLERS;
110 snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0);
111 }
112 return 0;
113}
114
115/*
116 * event input callback - just redirect events to subscribers
117 */
118static int
119dummy_input(snd_seq_event_t *ev, int direct, void *private_data, int atomic, int hop)
120{
121 snd_seq_dummy_port_t *p;
122 snd_seq_event_t tmpev;
123
124 p = private_data;
125 if (ev->source.client == SNDRV_SEQ_CLIENT_SYSTEM ||
126 ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
127 return 0; /* ignore system messages */
128 tmpev = *ev;
129 if (p->duplex)
130 tmpev.source.port = p->connect;
131 else
132 tmpev.source.port = p->port;
133 tmpev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
134 return snd_seq_kernel_client_dispatch(p->client, &tmpev, atomic, hop);
135}
136
137/*
138 * free_private callback
139 */
140static void
141dummy_free(void *private_data)
142{
143 snd_seq_dummy_port_t *p;
144
145 p = private_data;
146 kfree(p);
147}
148
149/*
150 * create a port
151 */
152static snd_seq_dummy_port_t __init *
153create_port(int idx, int type)
154{
155 snd_seq_port_info_t pinfo;
156 snd_seq_port_callback_t pcb;
157 snd_seq_dummy_port_t *rec;
158
159 if ((rec = kcalloc(1, sizeof(*rec), GFP_KERNEL)) == NULL)
160 return NULL;
161
162 rec->client = my_client;
163 rec->duplex = duplex;
164 rec->connect = 0;
165 memset(&pinfo, 0, sizeof(pinfo));
166 pinfo.addr.client = my_client;
167 if (duplex)
168 sprintf(pinfo.name, "Midi Through Port-%d:%c", idx,
169 (type ? 'B' : 'A'));
170 else
171 sprintf(pinfo.name, "Midi Through Port-%d", idx);
172 pinfo.capability = SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
173 pinfo.capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
174 if (duplex)
175 pinfo.capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
176 pinfo.type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
177 memset(&pcb, 0, sizeof(pcb));
178 pcb.owner = THIS_MODULE;
179 pcb.unuse = dummy_unuse;
180 pcb.event_input = dummy_input;
181 pcb.private_free = dummy_free;
182 pcb.private_data = rec;
183 pinfo.kernel = &pcb;
184 if (snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo) < 0) {
185 kfree(rec);
186 return NULL;
187 }
188 rec->port = pinfo.addr.port;
189 return rec;
190}
191
192/*
193 * register client and create ports
194 */
195static int __init
196register_client(void)
197{
198 snd_seq_client_callback_t cb;
199 snd_seq_client_info_t cinfo;
200 snd_seq_dummy_port_t *rec1, *rec2;
201 int i;
202
203 if (ports < 1) {
204 snd_printk(KERN_ERR "invalid number of ports %d\n", ports);
205 return -EINVAL;
206 }
207
208 /* create client */
209 memset(&cb, 0, sizeof(cb));
210 cb.allow_input = 1;
211 cb.allow_output = 1;
212 my_client = snd_seq_create_kernel_client(NULL, SNDRV_SEQ_CLIENT_DUMMY, &cb);
213 if (my_client < 0)
214 return my_client;
215
216 /* set client name */
217 memset(&cinfo, 0, sizeof(cinfo));
218 cinfo.client = my_client;
219 cinfo.type = KERNEL_CLIENT;
220 strcpy(cinfo.name, "Midi Through");
221 snd_seq_kernel_client_ctl(my_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
222
223 /* create ports */
224 for (i = 0; i < ports; i++) {
225 rec1 = create_port(i, 0);
226 if (rec1 == NULL) {
227 snd_seq_delete_kernel_client(my_client);
228 return -ENOMEM;
229 }
230 if (duplex) {
231 rec2 = create_port(i, 1);
232 if (rec2 == NULL) {
233 snd_seq_delete_kernel_client(my_client);
234 return -ENOMEM;
235 }
236 rec1->connect = rec2->port;
237 rec2->connect = rec1->port;
238 }
239 }
240
241 return 0;
242}
243
244/*
245 * delete client if exists
246 */
247static void __exit
248delete_client(void)
249{
250 if (my_client >= 0)
251 snd_seq_delete_kernel_client(my_client);
252}
253
254/*
255 * Init part
256 */
257
258static int __init alsa_seq_dummy_init(void)
259{
260 int err;
261 snd_seq_autoload_lock();
262 err = register_client();
263 snd_seq_autoload_unlock();
264 return err;
265}
266
267static void __exit alsa_seq_dummy_exit(void)
268{
269 delete_client();
270}
271
272module_init(alsa_seq_dummy_init)
273module_exit(alsa_seq_dummy_exit)
diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
new file mode 100644
index 000000000000..3b7647ca7ad9
--- /dev/null
+++ b/sound/core/seq/seq_fifo.c
@@ -0,0 +1,264 @@
1/*
2 * ALSA sequencer FIFO
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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 <sound/core.h>
24#include <linux/slab.h>
25#include "seq_fifo.h"
26#include "seq_lock.h"
27
28
29/* FIFO */
30
31/* create new fifo */
32fifo_t *snd_seq_fifo_new(int poolsize)
33{
34 fifo_t *f;
35
36 f = kcalloc(1, sizeof(*f), GFP_KERNEL);
37 if (f == NULL) {
38 snd_printd("malloc failed for snd_seq_fifo_new() \n");
39 return NULL;
40 }
41
42 f->pool = snd_seq_pool_new(poolsize);
43 if (f->pool == NULL) {
44 kfree(f);
45 return NULL;
46 }
47 if (snd_seq_pool_init(f->pool) < 0) {
48 snd_seq_pool_delete(&f->pool);
49 kfree(f);
50 return NULL;
51 }
52
53 spin_lock_init(&f->lock);
54 snd_use_lock_init(&f->use_lock);
55 init_waitqueue_head(&f->input_sleep);
56 atomic_set(&f->overflow, 0);
57
58 f->head = NULL;
59 f->tail = NULL;
60 f->cells = 0;
61
62 return f;
63}
64
65void snd_seq_fifo_delete(fifo_t **fifo)
66{
67 fifo_t *f;
68
69 snd_assert(fifo != NULL, return);
70 f = *fifo;
71 snd_assert(f != NULL, return);
72 *fifo = NULL;
73
74 snd_seq_fifo_clear(f);
75
76 /* wake up clients if any */
77 if (waitqueue_active(&f->input_sleep))
78 wake_up(&f->input_sleep);
79
80 /* release resources...*/
81 /*....................*/
82
83 if (f->pool) {
84 snd_seq_pool_done(f->pool);
85 snd_seq_pool_delete(&f->pool);
86 }
87
88 kfree(f);
89}
90
91static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f);
92
93/* clear queue */
94void snd_seq_fifo_clear(fifo_t *f)
95{
96 snd_seq_event_cell_t *cell;
97 unsigned long flags;
98
99 /* clear overflow flag */
100 atomic_set(&f->overflow, 0);
101
102 snd_use_lock_sync(&f->use_lock);
103 spin_lock_irqsave(&f->lock, flags);
104 /* drain the fifo */
105 while ((cell = fifo_cell_out(f)) != NULL) {
106 snd_seq_cell_free(cell);
107 }
108 spin_unlock_irqrestore(&f->lock, flags);
109}
110
111
112/* enqueue event to fifo */
113int snd_seq_fifo_event_in(fifo_t *f, snd_seq_event_t *event)
114{
115 snd_seq_event_cell_t *cell;
116 unsigned long flags;
117 int err;
118
119 snd_assert(f != NULL, return -EINVAL);
120
121 snd_use_lock_use(&f->use_lock);
122 err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
123 if (err < 0) {
124 if (err == -ENOMEM)
125 atomic_inc(&f->overflow);
126 snd_use_lock_free(&f->use_lock);
127 return err;
128 }
129
130 /* append new cells to fifo */
131 spin_lock_irqsave(&f->lock, flags);
132 if (f->tail != NULL)
133 f->tail->next = cell;
134 f->tail = cell;
135 if (f->head == NULL)
136 f->head = cell;
137 f->cells++;
138 spin_unlock_irqrestore(&f->lock, flags);
139
140 /* wakeup client */
141 if (waitqueue_active(&f->input_sleep))
142 wake_up(&f->input_sleep);
143
144 snd_use_lock_free(&f->use_lock);
145
146 return 0; /* success */
147
148}
149
150/* dequeue cell from fifo */
151static snd_seq_event_cell_t *fifo_cell_out(fifo_t *f)
152{
153 snd_seq_event_cell_t *cell;
154
155 if ((cell = f->head) != NULL) {
156 f->head = cell->next;
157
158 /* reset tail if this was the last element */
159 if (f->tail == cell)
160 f->tail = NULL;
161
162 cell->next = NULL;
163 f->cells--;
164 }
165
166 return cell;
167}
168
169/* dequeue cell from fifo and copy on user space */
170int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock)
171{
172 snd_seq_event_cell_t *cell;
173 unsigned long flags;
174 wait_queue_t wait;
175
176 snd_assert(f != NULL, return -EINVAL);
177
178 *cellp = NULL;
179 init_waitqueue_entry(&wait, current);
180 spin_lock_irqsave(&f->lock, flags);
181 while ((cell = fifo_cell_out(f)) == NULL) {
182 if (nonblock) {
183 /* non-blocking - return immediately */
184 spin_unlock_irqrestore(&f->lock, flags);
185 return -EAGAIN;
186 }
187 set_current_state(TASK_INTERRUPTIBLE);
188 add_wait_queue(&f->input_sleep, &wait);
189 spin_unlock_irq(&f->lock);
190 schedule();
191 spin_lock_irq(&f->lock);
192 remove_wait_queue(&f->input_sleep, &wait);
193 if (signal_pending(current)) {
194 spin_unlock_irqrestore(&f->lock, flags);
195 return -ERESTARTSYS;
196 }
197 }
198 spin_unlock_irqrestore(&f->lock, flags);
199 *cellp = cell;
200
201 return 0;
202}
203
204
205void snd_seq_fifo_cell_putback(fifo_t *f, snd_seq_event_cell_t *cell)
206{
207 unsigned long flags;
208
209 if (cell) {
210 spin_lock_irqsave(&f->lock, flags);
211 cell->next = f->head;
212 f->head = cell;
213 f->cells++;
214 spin_unlock_irqrestore(&f->lock, flags);
215 }
216}
217
218
219/* polling; return non-zero if queue is available */
220int snd_seq_fifo_poll_wait(fifo_t *f, struct file *file, poll_table *wait)
221{
222 poll_wait(file, &f->input_sleep, wait);
223 return (f->cells > 0);
224}
225
226/* change the size of pool; all old events are removed */
227int snd_seq_fifo_resize(fifo_t *f, int poolsize)
228{
229 unsigned long flags;
230 pool_t *newpool, *oldpool;
231 snd_seq_event_cell_t *cell, *next, *oldhead;
232
233 snd_assert(f != NULL && f->pool != NULL, return -EINVAL);
234
235 /* allocate new pool */
236 newpool = snd_seq_pool_new(poolsize);
237 if (newpool == NULL)
238 return -ENOMEM;
239 if (snd_seq_pool_init(newpool) < 0) {
240 snd_seq_pool_delete(&newpool);
241 return -ENOMEM;
242 }
243
244 spin_lock_irqsave(&f->lock, flags);
245 /* remember old pool */
246 oldpool = f->pool;
247 oldhead = f->head;
248 /* exchange pools */
249 f->pool = newpool;
250 f->head = NULL;
251 f->tail = NULL;
252 f->cells = 0;
253 /* NOTE: overflow flag is not cleared */
254 spin_unlock_irqrestore(&f->lock, flags);
255
256 /* release cells in old pool */
257 for (cell = oldhead; cell; cell = next) {
258 next = cell->next;
259 snd_seq_cell_free(cell);
260 }
261 snd_seq_pool_delete(&oldpool);
262
263 return 0;
264}
diff --git a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h
new file mode 100644
index 000000000000..d677c261b0a4
--- /dev/null
+++ b/sound/core/seq/seq_fifo.h
@@ -0,0 +1,72 @@
1/*
2 * ALSA sequencer FIFO
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_FIFO_H
22#define __SND_SEQ_FIFO_H
23
24#include "seq_memory.h"
25#include "seq_lock.h"
26
27
28/* === FIFO === */
29
30typedef struct {
31 pool_t *pool; /* FIFO pool */
32 snd_seq_event_cell_t* head; /* pointer to head of fifo */
33 snd_seq_event_cell_t* tail; /* pointer to tail of fifo */
34 int cells;
35 spinlock_t lock;
36 snd_use_lock_t use_lock;
37 wait_queue_head_t input_sleep;
38 atomic_t overflow;
39
40} fifo_t;
41
42/* create new fifo (constructor) */
43extern fifo_t *snd_seq_fifo_new(int poolsize);
44
45/* delete fifo (destructor) */
46extern void snd_seq_fifo_delete(fifo_t **f);
47
48
49/* enqueue event to fifo */
50extern int snd_seq_fifo_event_in(fifo_t *f, snd_seq_event_t *event);
51
52/* lock fifo from release */
53#define snd_seq_fifo_lock(fifo) snd_use_lock_use(&(fifo)->use_lock)
54#define snd_seq_fifo_unlock(fifo) snd_use_lock_free(&(fifo)->use_lock)
55
56/* get a cell from fifo - fifo should be locked */
57int snd_seq_fifo_cell_out(fifo_t *f, snd_seq_event_cell_t **cellp, int nonblock);
58
59/* free dequeued cell - fifo should be locked */
60extern void snd_seq_fifo_cell_putback(fifo_t *f, snd_seq_event_cell_t *cell);
61
62/* clean up queue */
63extern void snd_seq_fifo_clear(fifo_t *f);
64
65/* polling */
66extern int snd_seq_fifo_poll_wait(fifo_t *f, struct file *file, poll_table *wait);
67
68/* resize pool in fifo */
69int snd_seq_fifo_resize(fifo_t *f, int poolsize);
70
71
72#endif
diff --git a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c
new file mode 100644
index 000000000000..b50b695c41c4
--- /dev/null
+++ b/sound/core/seq/seq_info.c
@@ -0,0 +1,75 @@
1/*
2 * ALSA sequencer /proc interface
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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 <sound/core.h>
25
26#include "seq_info.h"
27#include "seq_clientmgr.h"
28#include "seq_timer.h"
29
30
31static snd_info_entry_t *queues_entry;
32static snd_info_entry_t *clients_entry;
33static snd_info_entry_t *timer_entry;
34
35
36static snd_info_entry_t * __init
37create_info_entry(char *name, int size, void (*read)(snd_info_entry_t *, snd_info_buffer_t *))
38{
39 snd_info_entry_t *entry;
40
41 entry = snd_info_create_module_entry(THIS_MODULE, name, snd_seq_root);
42 if (entry == NULL)
43 return NULL;
44 entry->content = SNDRV_INFO_CONTENT_TEXT;
45 entry->c.text.read_size = size;
46 entry->c.text.read = read;
47 if (snd_info_register(entry) < 0) {
48 snd_info_free_entry(entry);
49 return NULL;
50 }
51 return entry;
52}
53
54
55/* create all our /proc entries */
56int __init snd_seq_info_init(void)
57{
58 queues_entry = create_info_entry("queues", 512 + (256 * SNDRV_SEQ_MAX_QUEUES),
59 snd_seq_info_queues_read);
60 clients_entry = create_info_entry("clients", 512 + (256 * SNDRV_SEQ_MAX_CLIENTS),
61 snd_seq_info_clients_read);
62 timer_entry = create_info_entry("timer", 1024, snd_seq_info_timer_read);
63 return 0;
64}
65
66int __exit snd_seq_info_done(void)
67{
68 if (queues_entry)
69 snd_info_unregister(queues_entry);
70 if (clients_entry)
71 snd_info_unregister(clients_entry);
72 if (timer_entry)
73 snd_info_unregister(timer_entry);
74 return 0;
75}
diff --git a/sound/core/seq/seq_info.h b/sound/core/seq/seq_info.h
new file mode 100644
index 000000000000..efd099a858e4
--- /dev/null
+++ b/sound/core/seq/seq_info.h
@@ -0,0 +1,36 @@
1/*
2 * ALSA sequencer /proc info
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_INFO_H
22#define __SND_SEQ_INFO_H
23
24#include <sound/info.h>
25#include <sound/seq_kernel.h>
26
27void snd_seq_info_clients_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
28void snd_seq_info_timer_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
29void snd_seq_info_queues_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer);
30
31
32int snd_seq_info_init( void );
33int snd_seq_info_done( void );
34
35
36#endif
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
new file mode 100644
index 000000000000..5b40ea2ba8f4
--- /dev/null
+++ b/sound/core/seq/seq_instr.c
@@ -0,0 +1,653 @@
1/*
2 * Generic Instrument routines for ALSA sequencer
3 * Copyright (c) 1999 by Jaroslav Kysela <perex@suse.cz>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <sound/driver.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <sound/core.h>
25#include "seq_clientmgr.h"
26#include <sound/seq_instr.h>
27#include <sound/initval.h>
28
29MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
30MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer instrument library.");
31MODULE_LICENSE("GPL");
32
33
34static void snd_instr_lock_ops(snd_seq_kinstr_list_t *list)
35{
36 if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
37 spin_lock_irqsave(&list->ops_lock, list->ops_flags);
38 } else {
39 down(&list->ops_mutex);
40 }
41}
42
43static void snd_instr_unlock_ops(snd_seq_kinstr_list_t *list)
44{
45 if (!(list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT)) {
46 spin_unlock_irqrestore(&list->ops_lock, list->ops_flags);
47 } else {
48 up(&list->ops_mutex);
49 }
50}
51
52static snd_seq_kinstr_t *snd_seq_instr_new(int add_len, int atomic)
53{
54 snd_seq_kinstr_t *instr;
55
56 instr = kcalloc(1, sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL);
57 if (instr == NULL)
58 return NULL;
59 instr->add_len = add_len;
60 return instr;
61}
62
63static int snd_seq_instr_free(snd_seq_kinstr_t *instr, int atomic)
64{
65 int result = 0;
66
67 if (instr == NULL)
68 return -EINVAL;
69 if (instr->ops && instr->ops->remove)
70 result = instr->ops->remove(instr->ops->private_data, instr, 1);
71 if (!result)
72 kfree(instr);
73 return result;
74}
75
76snd_seq_kinstr_list_t *snd_seq_instr_list_new(void)
77{
78 snd_seq_kinstr_list_t *list;
79
80 list = kcalloc(1, sizeof(snd_seq_kinstr_list_t), GFP_KERNEL);
81 if (list == NULL)
82 return NULL;
83 spin_lock_init(&list->lock);
84 spin_lock_init(&list->ops_lock);
85 init_MUTEX(&list->ops_mutex);
86 list->owner = -1;
87 return list;
88}
89
90void snd_seq_instr_list_free(snd_seq_kinstr_list_t **list_ptr)
91{
92 snd_seq_kinstr_list_t *list;
93 snd_seq_kinstr_t *instr;
94 snd_seq_kcluster_t *cluster;
95 int idx;
96 unsigned long flags;
97
98 if (list_ptr == NULL)
99 return;
100 list = *list_ptr;
101 *list_ptr = NULL;
102 if (list == NULL)
103 return;
104
105 for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) {
106 while ((instr = list->hash[idx]) != NULL) {
107 list->hash[idx] = instr->next;
108 list->count--;
109 spin_lock_irqsave(&list->lock, flags);
110 while (instr->use) {
111 spin_unlock_irqrestore(&list->lock, flags);
112 set_current_state(TASK_INTERRUPTIBLE);
113 schedule_timeout(1);
114 spin_lock_irqsave(&list->lock, flags);
115 }
116 spin_unlock_irqrestore(&list->lock, flags);
117 if (snd_seq_instr_free(instr, 0)<0)
118 snd_printk(KERN_WARNING "instrument free problem\n");
119 }
120 while ((cluster = list->chash[idx]) != NULL) {
121 list->chash[idx] = cluster->next;
122 list->ccount--;
123 kfree(cluster);
124 }
125 }
126 kfree(list);
127}
128
129static int instr_free_compare(snd_seq_kinstr_t *instr,
130 snd_seq_instr_header_t *ifree,
131 unsigned int client)
132{
133 switch (ifree->cmd) {
134 case SNDRV_SEQ_INSTR_FREE_CMD_ALL:
135 /* all, except private for other clients */
136 if ((instr->instr.std & 0xff000000) == 0)
137 return 0;
138 if (((instr->instr.std >> 24) & 0xff) == client)
139 return 0;
140 return 1;
141 case SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE:
142 /* all my private instruments */
143 if ((instr->instr.std & 0xff000000) == 0)
144 return 1;
145 if (((instr->instr.std >> 24) & 0xff) == client)
146 return 0;
147 return 1;
148 case SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER:
149 /* all my private instruments */
150 if ((instr->instr.std & 0xff000000) == 0) {
151 if (instr->instr.cluster == ifree->id.cluster)
152 return 0;
153 return 1;
154 }
155 if (((instr->instr.std >> 24) & 0xff) == client) {
156 if (instr->instr.cluster == ifree->id.cluster)
157 return 0;
158 }
159 return 1;
160 }
161 return 1;
162}
163
164int snd_seq_instr_list_free_cond(snd_seq_kinstr_list_t *list,
165 snd_seq_instr_header_t *ifree,
166 int client,
167 int atomic)
168{
169 snd_seq_kinstr_t *instr, *prev, *next, *flist;
170 int idx;
171 unsigned long flags;
172
173 snd_instr_lock_ops(list);
174 for (idx = 0; idx < SNDRV_SEQ_INSTR_HASH_SIZE; idx++) {
175 spin_lock_irqsave(&list->lock, flags);
176 instr = list->hash[idx];
177 prev = flist = NULL;
178 while (instr) {
179 while (instr && instr_free_compare(instr, ifree, (unsigned int)client)) {
180 prev = instr;
181 instr = instr->next;
182 }
183 if (instr == NULL)
184 continue;
185 if (instr->ops && instr->ops->notify)
186 instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
187 next = instr->next;
188 if (prev == NULL) {
189 list->hash[idx] = next;
190 } else {
191 prev->next = next;
192 }
193 list->count--;
194 instr->next = flist;
195 flist = instr;
196 instr = next;
197 }
198 spin_unlock_irqrestore(&list->lock, flags);
199 while (flist) {
200 instr = flist;
201 flist = instr->next;
202 while (instr->use) {
203 set_current_state(TASK_INTERRUPTIBLE);
204 schedule_timeout(1);
205 }
206 if (snd_seq_instr_free(instr, atomic)<0)
207 snd_printk(KERN_WARNING "instrument free problem\n");
208 instr = next;
209 }
210 }
211 snd_instr_unlock_ops(list);
212 return 0;
213}
214
215static int compute_hash_instr_key(snd_seq_instr_t *instr)
216{
217 int result;
218
219 result = instr->bank | (instr->prg << 16);
220 result += result >> 24;
221 result += result >> 16;
222 result += result >> 8;
223 return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);
224}
225
226#if 0
227static int compute_hash_cluster_key(snd_seq_instr_cluster_t cluster)
228{
229 int result;
230
231 result = cluster;
232 result += result >> 24;
233 result += result >> 16;
234 result += result >> 8;
235 return result & (SNDRV_SEQ_INSTR_HASH_SIZE-1);
236}
237#endif
238
239static int compare_instr(snd_seq_instr_t *i1, snd_seq_instr_t *i2, int exact)
240{
241 if (exact) {
242 if (i1->cluster != i2->cluster ||
243 i1->bank != i2->bank ||
244 i1->prg != i2->prg)
245 return 1;
246 if ((i1->std & 0xff000000) != (i2->std & 0xff000000))
247 return 1;
248 if (!(i1->std & i2->std))
249 return 1;
250 return 0;
251 } else {
252 unsigned int client_check;
253
254 if (i2->cluster && i1->cluster != i2->cluster)
255 return 1;
256 client_check = i2->std & 0xff000000;
257 if (client_check) {
258 if ((i1->std & 0xff000000) != client_check)
259 return 1;
260 } else {
261 if ((i1->std & i2->std) != i2->std)
262 return 1;
263 }
264 return i1->bank != i2->bank || i1->prg != i2->prg;
265 }
266}
267
268snd_seq_kinstr_t *snd_seq_instr_find(snd_seq_kinstr_list_t *list,
269 snd_seq_instr_t *instr,
270 int exact,
271 int follow_alias)
272{
273 unsigned long flags;
274 int depth = 0;
275 snd_seq_kinstr_t *result;
276
277 if (list == NULL || instr == NULL)
278 return NULL;
279 spin_lock_irqsave(&list->lock, flags);
280 __again:
281 result = list->hash[compute_hash_instr_key(instr)];
282 while (result) {
283 if (!compare_instr(&result->instr, instr, exact)) {
284 if (follow_alias && (result->type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)) {
285 instr = (snd_seq_instr_t *)KINSTR_DATA(result);
286 if (++depth > 10)
287 goto __not_found;
288 goto __again;
289 }
290 result->use++;
291 spin_unlock_irqrestore(&list->lock, flags);
292 return result;
293 }
294 result = result->next;
295 }
296 __not_found:
297 spin_unlock_irqrestore(&list->lock, flags);
298 return NULL;
299}
300
301void snd_seq_instr_free_use(snd_seq_kinstr_list_t *list,
302 snd_seq_kinstr_t *instr)
303{
304 unsigned long flags;
305
306 if (list == NULL || instr == NULL)
307 return;
308 spin_lock_irqsave(&list->lock, flags);
309 if (instr->use <= 0) {
310 snd_printk(KERN_ERR "free_use: fatal!!! use = %i, name = '%s'\n", instr->use, instr->name);
311 } else {
312 instr->use--;
313 }
314 spin_unlock_irqrestore(&list->lock, flags);
315}
316
317static snd_seq_kinstr_ops_t *instr_ops(snd_seq_kinstr_ops_t *ops, char *instr_type)
318{
319 while (ops) {
320 if (!strcmp(ops->instr_type, instr_type))
321 return ops;
322 ops = ops->next;
323 }
324 return NULL;
325}
326
327static int instr_result(snd_seq_event_t *ev,
328 int type, int result,
329 int atomic)
330{
331 snd_seq_event_t sev;
332
333 memset(&sev, 0, sizeof(sev));
334 sev.type = SNDRV_SEQ_EVENT_RESULT;
335 sev.flags = SNDRV_SEQ_TIME_STAMP_REAL | SNDRV_SEQ_EVENT_LENGTH_FIXED |
336 SNDRV_SEQ_PRIORITY_NORMAL;
337 sev.source = ev->dest;
338 sev.dest = ev->source;
339 sev.data.result.event = type;
340 sev.data.result.result = result;
341#if 0
342 printk("instr result - type = %i, result = %i, queue = %i, source.client:port = %i:%i, dest.client:port = %i:%i\n",
343 type, result,
344 sev.queue,
345 sev.source.client, sev.source.port,
346 sev.dest.client, sev.dest.port);
347#endif
348 return snd_seq_kernel_client_dispatch(sev.source.client, &sev, atomic, 0);
349}
350
351static int instr_begin(snd_seq_kinstr_ops_t *ops,
352 snd_seq_kinstr_list_t *list,
353 snd_seq_event_t *ev,
354 int atomic, int hop)
355{
356 unsigned long flags;
357
358 spin_lock_irqsave(&list->lock, flags);
359 if (list->owner >= 0 && list->owner != ev->source.client) {
360 spin_unlock_irqrestore(&list->lock, flags);
361 return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, -EBUSY, atomic);
362 }
363 list->owner = ev->source.client;
364 spin_unlock_irqrestore(&list->lock, flags);
365 return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_BEGIN, 0, atomic);
366}
367
368static int instr_end(snd_seq_kinstr_ops_t *ops,
369 snd_seq_kinstr_list_t *list,
370 snd_seq_event_t *ev,
371 int atomic, int hop)
372{
373 unsigned long flags;
374
375 /* TODO: timeout handling */
376 spin_lock_irqsave(&list->lock, flags);
377 if (list->owner == ev->source.client) {
378 list->owner = -1;
379 spin_unlock_irqrestore(&list->lock, flags);
380 return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, 0, atomic);
381 }
382 spin_unlock_irqrestore(&list->lock, flags);
383 return instr_result(ev, SNDRV_SEQ_EVENT_INSTR_END, -EINVAL, atomic);
384}
385
386static int instr_info(snd_seq_kinstr_ops_t *ops,
387 snd_seq_kinstr_list_t *list,
388 snd_seq_event_t *ev,
389 int atomic, int hop)
390{
391 return -ENXIO;
392}
393
394static int instr_format_info(snd_seq_kinstr_ops_t *ops,
395 snd_seq_kinstr_list_t *list,
396 snd_seq_event_t *ev,
397 int atomic, int hop)
398{
399 return -ENXIO;
400}
401
402static int instr_reset(snd_seq_kinstr_ops_t *ops,
403 snd_seq_kinstr_list_t *list,
404 snd_seq_event_t *ev,
405 int atomic, int hop)
406{
407 return -ENXIO;
408}
409
410static int instr_status(snd_seq_kinstr_ops_t *ops,
411 snd_seq_kinstr_list_t *list,
412 snd_seq_event_t *ev,
413 int atomic, int hop)
414{
415 return -ENXIO;
416}
417
418static int instr_put(snd_seq_kinstr_ops_t *ops,
419 snd_seq_kinstr_list_t *list,
420 snd_seq_event_t *ev,
421 int atomic, int hop)
422{
423 unsigned long flags;
424 snd_seq_instr_header_t put;
425 snd_seq_kinstr_t *instr;
426 int result = -EINVAL, len, key;
427
428 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR)
429 goto __return;
430
431 if (ev->data.ext.len < sizeof(snd_seq_instr_header_t))
432 goto __return;
433 if (copy_from_user(&put, (void __user *)ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
434 result = -EFAULT;
435 goto __return;
436 }
437 snd_instr_lock_ops(list);
438 if (put.id.instr.std & 0xff000000) { /* private instrument */
439 put.id.instr.std &= 0x00ffffff;
440 put.id.instr.std |= (unsigned int)ev->source.client << 24;
441 }
442 if ((instr = snd_seq_instr_find(list, &put.id.instr, 1, 0))) {
443 snd_seq_instr_free_use(list, instr);
444 snd_instr_unlock_ops(list);
445 result = -EBUSY;
446 goto __return;
447 }
448 ops = instr_ops(ops, put.data.data.format);
449 if (ops == NULL) {
450 snd_instr_unlock_ops(list);
451 goto __return;
452 }
453 len = ops->add_len;
454 if (put.data.type == SNDRV_SEQ_INSTR_ATYPE_ALIAS)
455 len = sizeof(snd_seq_instr_t);
456 instr = snd_seq_instr_new(len, atomic);
457 if (instr == NULL) {
458 snd_instr_unlock_ops(list);
459 result = -ENOMEM;
460 goto __return;
461 }
462 instr->ops = ops;
463 instr->instr = put.id.instr;
464 strlcpy(instr->name, put.data.name, sizeof(instr->name));
465 instr->type = put.data.type;
466 if (instr->type == SNDRV_SEQ_INSTR_ATYPE_DATA) {
467 result = ops->put(ops->private_data,
468 instr,
469 (void __user *)ev->data.ext.ptr + sizeof(snd_seq_instr_header_t),
470 ev->data.ext.len - sizeof(snd_seq_instr_header_t),
471 atomic,
472 put.cmd);
473 if (result < 0) {
474 snd_seq_instr_free(instr, atomic);
475 snd_instr_unlock_ops(list);
476 goto __return;
477 }
478 }
479 key = compute_hash_instr_key(&instr->instr);
480 spin_lock_irqsave(&list->lock, flags);
481 instr->next = list->hash[key];
482 list->hash[key] = instr;
483 list->count++;
484 spin_unlock_irqrestore(&list->lock, flags);
485 snd_instr_unlock_ops(list);
486 result = 0;
487 __return:
488 instr_result(ev, SNDRV_SEQ_EVENT_INSTR_PUT, result, atomic);
489 return result;
490}
491
492static int instr_get(snd_seq_kinstr_ops_t *ops,
493 snd_seq_kinstr_list_t *list,
494 snd_seq_event_t *ev,
495 int atomic, int hop)
496{
497 return -ENXIO;
498}
499
500static int instr_free(snd_seq_kinstr_ops_t *ops,
501 snd_seq_kinstr_list_t *list,
502 snd_seq_event_t *ev,
503 int atomic, int hop)
504{
505 snd_seq_instr_header_t ifree;
506 snd_seq_kinstr_t *instr, *prev;
507 int result = -EINVAL;
508 unsigned long flags;
509 unsigned int hash;
510
511 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARUSR)
512 goto __return;
513
514 if (ev->data.ext.len < sizeof(snd_seq_instr_header_t))
515 goto __return;
516 if (copy_from_user(&ifree, (void __user *)ev->data.ext.ptr, sizeof(snd_seq_instr_header_t))) {
517 result = -EFAULT;
518 goto __return;
519 }
520 if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_ALL ||
521 ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_PRIVATE ||
522 ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_CLUSTER) {
523 result = snd_seq_instr_list_free_cond(list, &ifree, ev->dest.client, atomic);
524 goto __return;
525 }
526 if (ifree.cmd == SNDRV_SEQ_INSTR_FREE_CMD_SINGLE) {
527 if (ifree.id.instr.std & 0xff000000) {
528 ifree.id.instr.std &= 0x00ffffff;
529 ifree.id.instr.std |= (unsigned int)ev->source.client << 24;
530 }
531 hash = compute_hash_instr_key(&ifree.id.instr);
532 snd_instr_lock_ops(list);
533 spin_lock_irqsave(&list->lock, flags);
534 instr = list->hash[hash];
535 prev = NULL;
536 while (instr) {
537 if (!compare_instr(&instr->instr, &ifree.id.instr, 1))
538 goto __free_single;
539 prev = instr;
540 instr = instr->next;
541 }
542 result = -ENOENT;
543 spin_unlock_irqrestore(&list->lock, flags);
544 snd_instr_unlock_ops(list);
545 goto __return;
546
547 __free_single:
548 if (prev) {
549 prev->next = instr->next;
550 } else {
551 list->hash[hash] = instr->next;
552 }
553 if (instr->ops && instr->ops->notify)
554 instr->ops->notify(instr->ops->private_data, instr, SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
555 while (instr->use) {
556 spin_unlock_irqrestore(&list->lock, flags);
557 set_current_state(TASK_INTERRUPTIBLE);
558 schedule_timeout(1);
559 spin_lock_irqsave(&list->lock, flags);
560 }
561 spin_unlock_irqrestore(&list->lock, flags);
562 result = snd_seq_instr_free(instr, atomic);
563 snd_instr_unlock_ops(list);
564 goto __return;
565 }
566
567 __return:
568 instr_result(ev, SNDRV_SEQ_EVENT_INSTR_FREE, result, atomic);
569 return result;
570}
571
572static int instr_list(snd_seq_kinstr_ops_t *ops,
573 snd_seq_kinstr_list_t *list,
574 snd_seq_event_t *ev,
575 int atomic, int hop)
576{
577 return -ENXIO;
578}
579
580static int instr_cluster(snd_seq_kinstr_ops_t *ops,
581 snd_seq_kinstr_list_t *list,
582 snd_seq_event_t *ev,
583 int atomic, int hop)
584{
585 return -ENXIO;
586}
587
588int snd_seq_instr_event(snd_seq_kinstr_ops_t *ops,
589 snd_seq_kinstr_list_t *list,
590 snd_seq_event_t *ev,
591 int client,
592 int atomic,
593 int hop)
594{
595 int direct = 0;
596
597 snd_assert(ops != NULL && list != NULL && ev != NULL, return -EINVAL);
598 if (snd_seq_ev_is_direct(ev)) {
599 direct = 1;
600 switch (ev->type) {
601 case SNDRV_SEQ_EVENT_INSTR_BEGIN:
602 return instr_begin(ops, list, ev, atomic, hop);
603 case SNDRV_SEQ_EVENT_INSTR_END:
604 return instr_end(ops, list, ev, atomic, hop);
605 }
606 }
607 if ((list->flags & SNDRV_SEQ_INSTR_FLG_DIRECT) && !direct)
608 return -EINVAL;
609 switch (ev->type) {
610 case SNDRV_SEQ_EVENT_INSTR_INFO:
611 return instr_info(ops, list, ev, atomic, hop);
612 case SNDRV_SEQ_EVENT_INSTR_FINFO:
613 return instr_format_info(ops, list, ev, atomic, hop);
614 case SNDRV_SEQ_EVENT_INSTR_RESET:
615 return instr_reset(ops, list, ev, atomic, hop);
616 case SNDRV_SEQ_EVENT_INSTR_STATUS:
617 return instr_status(ops, list, ev, atomic, hop);
618 case SNDRV_SEQ_EVENT_INSTR_PUT:
619 return instr_put(ops, list, ev, atomic, hop);
620 case SNDRV_SEQ_EVENT_INSTR_GET:
621 return instr_get(ops, list, ev, atomic, hop);
622 case SNDRV_SEQ_EVENT_INSTR_FREE:
623 return instr_free(ops, list, ev, atomic, hop);
624 case SNDRV_SEQ_EVENT_INSTR_LIST:
625 return instr_list(ops, list, ev, atomic, hop);
626 case SNDRV_SEQ_EVENT_INSTR_CLUSTER:
627 return instr_cluster(ops, list, ev, atomic, hop);
628 }
629 return -EINVAL;
630}
631
632/*
633 * Init part
634 */
635
636static int __init alsa_seq_instr_init(void)
637{
638 return 0;
639}
640
641static void __exit alsa_seq_instr_exit(void)
642{
643}
644
645module_init(alsa_seq_instr_init)
646module_exit(alsa_seq_instr_exit)
647
648EXPORT_SYMBOL(snd_seq_instr_list_new);
649EXPORT_SYMBOL(snd_seq_instr_list_free);
650EXPORT_SYMBOL(snd_seq_instr_list_free_cond);
651EXPORT_SYMBOL(snd_seq_instr_find);
652EXPORT_SYMBOL(snd_seq_instr_free_use);
653EXPORT_SYMBOL(snd_seq_instr_event);
diff --git a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
new file mode 100644
index 000000000000..b09cee058fa7
--- /dev/null
+++ b/sound/core/seq/seq_lock.c
@@ -0,0 +1,48 @@
1/*
2 * Do sleep inside a spin-lock
3 * Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de>
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 <sound/core.h>
24#include "seq_lock.h"
25
26#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
27
28/* wait until all locks are released */
29void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
30{
31 int max_count = 5 * HZ;
32
33 if (atomic_read(lockp) < 0) {
34 printk(KERN_WARNING "seq_lock: lock trouble [counter = %d] in %s:%d\n", atomic_read(lockp), file, line);
35 return;
36 }
37 while (atomic_read(lockp) > 0) {
38 if (max_count == 0) {
39 snd_printk(KERN_WARNING "seq_lock: timeout [%d left] in %s:%d\n", atomic_read(lockp), file, line);
40 break;
41 }
42 set_current_state(TASK_UNINTERRUPTIBLE);
43 schedule_timeout(1);
44 max_count--;
45 }
46}
47
48#endif
diff --git a/sound/core/seq/seq_lock.h b/sound/core/seq/seq_lock.h
new file mode 100644
index 000000000000..54044bc2c9ef
--- /dev/null
+++ b/sound/core/seq/seq_lock.h
@@ -0,0 +1,33 @@
1#ifndef __SND_SEQ_LOCK_H
2#define __SND_SEQ_LOCK_H
3
4#include <linux/sched.h>
5
6#if defined(CONFIG_SMP) || defined(CONFIG_SND_DEBUG)
7
8typedef atomic_t snd_use_lock_t;
9
10/* initialize lock */
11#define snd_use_lock_init(lockp) atomic_set(lockp, 0)
12
13/* increment lock */
14#define snd_use_lock_use(lockp) atomic_inc(lockp)
15
16/* release lock */
17#define snd_use_lock_free(lockp) atomic_dec(lockp)
18
19/* wait until all locks are released */
20void snd_use_lock_sync_helper(snd_use_lock_t *lock, const char *file, int line);
21#define snd_use_lock_sync(lockp) snd_use_lock_sync_helper(lockp, __BASE_FILE__, __LINE__)
22
23#else /* SMP || CONFIG_SND_DEBUG */
24
25typedef spinlock_t snd_use_lock_t; /* dummy */
26#define snd_use_lock_init(lockp) /**/
27#define snd_use_lock_use(lockp) /**/
28#define snd_use_lock_free(lockp) /**/
29#define snd_use_lock_sync(lockp) /**/
30
31#endif /* SMP || CONFIG_SND_DEBUG */
32
33#endif /* __SND_SEQ_LOCK_H */
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
new file mode 100644
index 000000000000..00d841e82fbc
--- /dev/null
+++ b/sound/core/seq/seq_memory.c
@@ -0,0 +1,510 @@
1/*
2 * ALSA sequencer Memory Manager
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
4 * Jaroslav Kysela <perex@suse.cz>
5 * 2000 by Takashi Iwai <tiwai@suse.de>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/vmalloc.h>
27#include <sound/core.h>
28
29#include <sound/seq_kernel.h>
30#include "seq_memory.h"
31#include "seq_queue.h"
32#include "seq_info.h"
33#include "seq_lock.h"
34
35/* semaphore in struct file record */
36#define semaphore_of(fp) ((fp)->f_dentry->d_inode->i_sem)
37
38
39inline static int snd_seq_pool_available(pool_t *pool)
40{
41 return pool->total_elements - atomic_read(&pool->counter);
42}
43
44inline static int snd_seq_output_ok(pool_t *pool)
45{
46 return snd_seq_pool_available(pool) >= pool->room;
47}
48
49/*
50 * Variable length event:
51 * The event like sysex uses variable length type.
52 * The external data may be stored in three different formats.
53 * 1) kernel space
54 * This is the normal case.
55 * ext.data.len = length
56 * ext.data.ptr = buffer pointer
57 * 2) user space
58 * When an event is generated via read(), the external data is
59 * kept in user space until expanded.
60 * ext.data.len = length | SNDRV_SEQ_EXT_USRPTR
61 * ext.data.ptr = userspace pointer
62 * 3) chained cells
63 * When the variable length event is enqueued (in prioq or fifo),
64 * the external data is decomposed to several cells.
65 * ext.data.len = length | SNDRV_SEQ_EXT_CHAINED
66 * ext.data.ptr = the additiona cell head
67 * -> cell.next -> cell.next -> ..
68 */
69
70/*
71 * exported:
72 * call dump function to expand external data.
73 */
74
75static int get_var_len(const snd_seq_event_t *event)
76{
77 if ((event->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
78 return -EINVAL;
79
80 return event->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
81}
82
83int snd_seq_dump_var_event(const snd_seq_event_t *event, snd_seq_dump_func_t func, void *private_data)
84{
85 int len, err;
86 snd_seq_event_cell_t *cell;
87
88 if ((len = get_var_len(event)) <= 0)
89 return len;
90
91 if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
92 char buf[32];
93 char __user *curptr = (char __user *)event->data.ext.ptr;
94 while (len > 0) {
95 int size = sizeof(buf);
96 if (len < size)
97 size = len;
98 if (copy_from_user(buf, curptr, size))
99 return -EFAULT;
100 err = func(private_data, buf, size);
101 if (err < 0)
102 return err;
103 curptr += size;
104 len -= size;
105 }
106 return 0;
107 } if (! (event->data.ext.len & SNDRV_SEQ_EXT_CHAINED)) {
108 return func(private_data, event->data.ext.ptr, len);
109 }
110
111 cell = (snd_seq_event_cell_t*)event->data.ext.ptr;
112 for (; len > 0 && cell; cell = cell->next) {
113 int size = sizeof(snd_seq_event_t);
114 if (len < size)
115 size = len;
116 err = func(private_data, &cell->event, size);
117 if (err < 0)
118 return err;
119 len -= size;
120 }
121 return 0;
122}
123
124
125/*
126 * exported:
127 * expand the variable length event to linear buffer space.
128 */
129
130static int seq_copy_in_kernel(char **bufptr, const void *src, int size)
131{
132 memcpy(*bufptr, src, size);
133 *bufptr += size;
134 return 0;
135}
136
137static int seq_copy_in_user(char __user **bufptr, const void *src, int size)
138{
139 if (copy_to_user(*bufptr, src, size))
140 return -EFAULT;
141 *bufptr += size;
142 return 0;
143}
144
145int snd_seq_expand_var_event(const snd_seq_event_t *event, int count, char *buf, int in_kernel, int size_aligned)
146{
147 int len, newlen;
148 int err;
149
150 if ((len = get_var_len(event)) < 0)
151 return len;
152 newlen = len;
153 if (size_aligned > 0)
154 newlen = ((len + size_aligned - 1) / size_aligned) * size_aligned;
155 if (count < newlen)
156 return -EAGAIN;
157
158 if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
159 if (! in_kernel)
160 return -EINVAL;
161 if (copy_from_user(buf, (void __user *)event->data.ext.ptr, len))
162 return -EFAULT;
163 return newlen;
164 }
165 err = snd_seq_dump_var_event(event,
166 in_kernel ? (snd_seq_dump_func_t)seq_copy_in_kernel :
167 (snd_seq_dump_func_t)seq_copy_in_user,
168 &buf);
169 return err < 0 ? err : newlen;
170}
171
172
173/*
174 * release this cell, free extended data if available
175 */
176
177static inline void free_cell(pool_t *pool, snd_seq_event_cell_t *cell)
178{
179 cell->next = pool->free;
180 pool->free = cell;
181 atomic_dec(&pool->counter);
182}
183
184void snd_seq_cell_free(snd_seq_event_cell_t * cell)
185{
186 unsigned long flags;
187 pool_t *pool;
188
189 snd_assert(cell != NULL, return);
190 pool = cell->pool;
191 snd_assert(pool != NULL, return);
192
193 spin_lock_irqsave(&pool->lock, flags);
194 free_cell(pool, cell);
195 if (snd_seq_ev_is_variable(&cell->event)) {
196 if (cell->event.data.ext.len & SNDRV_SEQ_EXT_CHAINED) {
197 snd_seq_event_cell_t *curp, *nextptr;
198 curp = cell->event.data.ext.ptr;
199 for (; curp; curp = nextptr) {
200 nextptr = curp->next;
201 curp->next = pool->free;
202 free_cell(pool, curp);
203 }
204 }
205 }
206 if (waitqueue_active(&pool->output_sleep)) {
207 /* has enough space now? */
208 if (snd_seq_output_ok(pool))
209 wake_up(&pool->output_sleep);
210 }
211 spin_unlock_irqrestore(&pool->lock, flags);
212}
213
214
215/*
216 * allocate an event cell.
217 */
218static int snd_seq_cell_alloc(pool_t *pool, snd_seq_event_cell_t **cellp, int nonblock, struct file *file)
219{
220 snd_seq_event_cell_t *cell;
221 unsigned long flags;
222 int err = -EAGAIN;
223 wait_queue_t wait;
224
225 if (pool == NULL)
226 return -EINVAL;
227
228 *cellp = NULL;
229
230 init_waitqueue_entry(&wait, current);
231 spin_lock_irqsave(&pool->lock, flags);
232 if (pool->ptr == NULL) { /* not initialized */
233 snd_printd("seq: pool is not initialized\n");
234 err = -EINVAL;
235 goto __error;
236 }
237 while (pool->free == NULL && ! nonblock && ! pool->closing) {
238
239 set_current_state(TASK_INTERRUPTIBLE);
240 add_wait_queue(&pool->output_sleep, &wait);
241 spin_unlock_irq(&pool->lock);
242 schedule();
243 spin_lock_irq(&pool->lock);
244 remove_wait_queue(&pool->output_sleep, &wait);
245 /* interrupted? */
246 if (signal_pending(current)) {
247 err = -ERESTARTSYS;
248 goto __error;
249 }
250 }
251 if (pool->closing) { /* closing.. */
252 err = -ENOMEM;
253 goto __error;
254 }
255
256 cell = pool->free;
257 if (cell) {
258 int used;
259 pool->free = cell->next;
260 atomic_inc(&pool->counter);
261 used = atomic_read(&pool->counter);
262 if (pool->max_used < used)
263 pool->max_used = used;
264 pool->event_alloc_success++;
265 /* clear cell pointers */
266 cell->next = NULL;
267 err = 0;
268 } else
269 pool->event_alloc_failures++;
270 *cellp = cell;
271
272__error:
273 spin_unlock_irqrestore(&pool->lock, flags);
274 return err;
275}
276
277
278/*
279 * duplicate the event to a cell.
280 * if the event has external data, the data is decomposed to additional
281 * cells.
282 */
283int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t **cellp, int nonblock, struct file *file)
284{
285 int ncells, err;
286 unsigned int extlen;
287 snd_seq_event_cell_t *cell;
288
289 *cellp = NULL;
290
291 ncells = 0;
292 extlen = 0;
293 if (snd_seq_ev_is_variable(event)) {
294 extlen = event->data.ext.len & ~SNDRV_SEQ_EXT_MASK;
295 ncells = (extlen + sizeof(snd_seq_event_t) - 1) / sizeof(snd_seq_event_t);
296 }
297 if (ncells >= pool->total_elements)
298 return -ENOMEM;
299
300 err = snd_seq_cell_alloc(pool, &cell, nonblock, file);
301 if (err < 0)
302 return err;
303
304 /* copy the event */
305 cell->event = *event;
306
307 /* decompose */
308 if (snd_seq_ev_is_variable(event)) {
309 int len = extlen;
310 int is_chained = event->data.ext.len & SNDRV_SEQ_EXT_CHAINED;
311 int is_usrptr = event->data.ext.len & SNDRV_SEQ_EXT_USRPTR;
312 snd_seq_event_cell_t *src, *tmp, *tail;
313 char *buf;
314
315 cell->event.data.ext.len = extlen | SNDRV_SEQ_EXT_CHAINED;
316 cell->event.data.ext.ptr = NULL;
317
318 src = (snd_seq_event_cell_t*)event->data.ext.ptr;
319 buf = (char *)event->data.ext.ptr;
320 tail = NULL;
321
322 while (ncells-- > 0) {
323 int size = sizeof(snd_seq_event_t);
324 if (len < size)
325 size = len;
326 err = snd_seq_cell_alloc(pool, &tmp, nonblock, file);
327 if (err < 0)
328 goto __error;
329 if (cell->event.data.ext.ptr == NULL)
330 cell->event.data.ext.ptr = tmp;
331 if (tail)
332 tail->next = tmp;
333 tail = tmp;
334 /* copy chunk */
335 if (is_chained && src) {
336 tmp->event = src->event;
337 src = src->next;
338 } else if (is_usrptr) {
339 if (copy_from_user(&tmp->event, (char __user *)buf, size)) {
340 err = -EFAULT;
341 goto __error;
342 }
343 } else {
344 memcpy(&tmp->event, buf, size);
345 }
346 buf += size;
347 len -= size;
348 }
349 }
350
351 *cellp = cell;
352 return 0;
353
354__error:
355 snd_seq_cell_free(cell);
356 return err;
357}
358
359
360/* poll wait */
361int snd_seq_pool_poll_wait(pool_t *pool, struct file *file, poll_table *wait)
362{
363 poll_wait(file, &pool->output_sleep, wait);
364 return snd_seq_output_ok(pool);
365}
366
367
368/* allocate room specified number of events */
369int snd_seq_pool_init(pool_t *pool)
370{
371 int cell;
372 snd_seq_event_cell_t *cellptr;
373 unsigned long flags;
374
375 snd_assert(pool != NULL, return -EINVAL);
376 if (pool->ptr) /* should be atomic? */
377 return 0;
378
379 pool->ptr = vmalloc(sizeof(snd_seq_event_cell_t) * pool->size);
380 if (pool->ptr == NULL) {
381 snd_printd("seq: malloc for sequencer events failed\n");
382 return -ENOMEM;
383 }
384
385 /* add new cells to the free cell list */
386 spin_lock_irqsave(&pool->lock, flags);
387 pool->free = NULL;
388
389 for (cell = 0; cell < pool->size; cell++) {
390 cellptr = pool->ptr + cell;
391 cellptr->pool = pool;
392 cellptr->next = pool->free;
393 pool->free = cellptr;
394 }
395 pool->room = (pool->size + 1) / 2;
396
397 /* init statistics */
398 pool->max_used = 0;
399 pool->total_elements = pool->size;
400 spin_unlock_irqrestore(&pool->lock, flags);
401 return 0;
402}
403
404/* remove events */
405int snd_seq_pool_done(pool_t *pool)
406{
407 unsigned long flags;
408 snd_seq_event_cell_t *ptr;
409 int max_count = 5 * HZ;
410
411 snd_assert(pool != NULL, return -EINVAL);
412
413 /* wait for closing all threads */
414 spin_lock_irqsave(&pool->lock, flags);
415 pool->closing = 1;
416 spin_unlock_irqrestore(&pool->lock, flags);
417
418 if (waitqueue_active(&pool->output_sleep))
419 wake_up(&pool->output_sleep);
420
421 while (atomic_read(&pool->counter) > 0) {
422 if (max_count == 0) {
423 snd_printk(KERN_WARNING "snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
424 break;
425 }
426 set_current_state(TASK_UNINTERRUPTIBLE);
427 schedule_timeout(1);
428 max_count--;
429 }
430
431 /* release all resources */
432 spin_lock_irqsave(&pool->lock, flags);
433 ptr = pool->ptr;
434 pool->ptr = NULL;
435 pool->free = NULL;
436 pool->total_elements = 0;
437 spin_unlock_irqrestore(&pool->lock, flags);
438
439 vfree(ptr);
440
441 spin_lock_irqsave(&pool->lock, flags);
442 pool->closing = 0;
443 spin_unlock_irqrestore(&pool->lock, flags);
444
445 return 0;
446}
447
448
449/* init new memory pool */
450pool_t *snd_seq_pool_new(int poolsize)
451{
452 pool_t *pool;
453
454 /* create pool block */
455 pool = kcalloc(1, sizeof(*pool), GFP_KERNEL);
456 if (pool == NULL) {
457 snd_printd("seq: malloc failed for pool\n");
458 return NULL;
459 }
460 spin_lock_init(&pool->lock);
461 pool->ptr = NULL;
462 pool->free = NULL;
463 pool->total_elements = 0;
464 atomic_set(&pool->counter, 0);
465 pool->closing = 0;
466 init_waitqueue_head(&pool->output_sleep);
467
468 pool->size = poolsize;
469
470 /* init statistics */
471 pool->max_used = 0;
472 return pool;
473}
474
475/* remove memory pool */
476int snd_seq_pool_delete(pool_t **ppool)
477{
478 pool_t *pool = *ppool;
479
480 *ppool = NULL;
481 if (pool == NULL)
482 return 0;
483 snd_seq_pool_done(pool);
484 kfree(pool);
485 return 0;
486}
487
488/* initialize sequencer memory */
489int __init snd_sequencer_memory_init(void)
490{
491 return 0;
492}
493
494/* release sequencer memory */
495void __exit snd_sequencer_memory_done(void)
496{
497}
498
499
500/* exported to seq_clientmgr.c */
501void snd_seq_info_pool(snd_info_buffer_t * buffer, pool_t *pool, char *space)
502{
503 if (pool == NULL)
504 return;
505 snd_iprintf(buffer, "%sPool size : %d\n", space, pool->total_elements);
506 snd_iprintf(buffer, "%sCells in use : %d\n", space, atomic_read(&pool->counter));
507 snd_iprintf(buffer, "%sPeak cells in use : %d\n", space, pool->max_used);
508 snd_iprintf(buffer, "%sAlloc success : %d\n", space, pool->event_alloc_success);
509 snd_iprintf(buffer, "%sAlloc failures : %d\n", space, pool->event_alloc_failures);
510}
diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h
new file mode 100644
index 000000000000..6c4dde5d3d6f
--- /dev/null
+++ b/sound/core/seq/seq_memory.h
@@ -0,0 +1,104 @@
1/*
2 * ALSA sequencer Memory Manager
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_MEMORYMGR_H
22#define __SND_SEQ_MEMORYMGR_H
23
24#include <sound/seq_kernel.h>
25#include <linux/poll.h>
26
27typedef struct pool pool_t;
28
29/* container for sequencer event (internal use) */
30typedef struct snd_seq_event_cell_t {
31 snd_seq_event_t event;
32 pool_t *pool; /* used pool */
33 struct snd_seq_event_cell_t *next; /* next cell */
34} snd_seq_event_cell_t;
35
36/* design note: the pool is a contigious block of memory, if we dynamicly
37 want to add additional cells to the pool be better store this in another
38 pool as we need to know the base address of the pool when releasing
39 memory. */
40
41struct pool {
42 snd_seq_event_cell_t *ptr; /* pointer to first event chunk */
43 snd_seq_event_cell_t *free; /* pointer to the head of the free list */
44
45 int total_elements; /* pool size actually allocated */
46 atomic_t counter; /* cells free */
47
48 int size; /* pool size to be allocated */
49 int room; /* watermark for sleep/wakeup */
50
51 int closing;
52
53 /* statistics */
54 int max_used;
55 int event_alloc_nopool;
56 int event_alloc_failures;
57 int event_alloc_success;
58
59 /* Write locking */
60 wait_queue_head_t output_sleep;
61
62 /* Pool lock */
63 spinlock_t lock;
64};
65
66extern void snd_seq_cell_free(snd_seq_event_cell_t* cell);
67
68int snd_seq_event_dup(pool_t *pool, snd_seq_event_t *event, snd_seq_event_cell_t **cellp, int nonblock, struct file *file);
69
70/* return number of unused (free) cells */
71static inline int snd_seq_unused_cells(pool_t *pool)
72{
73 return pool ? pool->total_elements - atomic_read(&pool->counter) : 0;
74}
75
76/* return total number of allocated cells */
77static inline int snd_seq_total_cells(pool_t *pool)
78{
79 return pool ? pool->total_elements : 0;
80}
81
82/* init pool - allocate events */
83int snd_seq_pool_init(pool_t *pool);
84
85/* done pool - free events */
86int snd_seq_pool_done(pool_t *pool);
87
88/* create pool */
89pool_t *snd_seq_pool_new(int poolsize);
90
91/* remove pool */
92int snd_seq_pool_delete(pool_t **pool);
93
94/* init memory */
95int snd_sequencer_memory_init(void);
96
97/* release event memory */
98void snd_sequencer_memory_done(void);
99
100/* polling */
101int snd_seq_pool_poll_wait(pool_t *pool, struct file *file, poll_table *wait);
102
103
104#endif
diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
new file mode 100644
index 000000000000..18247db45db6
--- /dev/null
+++ b/sound/core/seq/seq_midi.c
@@ -0,0 +1,489 @@
1/*
2 * Generic MIDI synth driver for ALSA sequencer
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
4 * Jaroslav Kysela <perex@suse.cz>
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/*
23Possible options for midisynth module:
24 - automatic opening of midi ports on first received event or subscription
25 (close will be performed when client leaves)
26*/
27
28
29#include <sound/driver.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/errno.h>
33#include <linux/string.h>
34#include <linux/moduleparam.h>
35#include <asm/semaphore.h>
36#include <sound/core.h>
37#include <sound/rawmidi.h>
38#include <sound/seq_kernel.h>
39#include <sound/seq_device.h>
40#include <sound/seq_midi_event.h>
41#include <sound/initval.h>
42
43MODULE_AUTHOR("Frank van de Pol <fvdpol@coil.demon.nl>, Jaroslav Kysela <perex@suse.cz>");
44MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
45MODULE_LICENSE("GPL");
46static int output_buffer_size = PAGE_SIZE;
47module_param(output_buffer_size, int, 0644);
48MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes.");
49static int input_buffer_size = PAGE_SIZE;
50module_param(input_buffer_size, int, 0644);
51MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
52
53/* data for this midi synth driver */
54typedef struct {
55 snd_card_t *card;
56 int device;
57 int subdevice;
58 snd_rawmidi_file_t input_rfile;
59 snd_rawmidi_file_t output_rfile;
60 int seq_client;
61 int seq_port;
62 snd_midi_event_t *parser;
63} seq_midisynth_t;
64
65typedef struct {
66 int seq_client;
67 int num_ports;
68 int ports_per_device[SNDRV_RAWMIDI_DEVICES];
69 seq_midisynth_t *ports[SNDRV_RAWMIDI_DEVICES];
70} seq_midisynth_client_t;
71
72static seq_midisynth_client_t *synths[SNDRV_CARDS];
73static DECLARE_MUTEX(register_mutex);
74
75/* handle rawmidi input event (MIDI v1.0 stream) */
76static void snd_midi_input_event(snd_rawmidi_substream_t * substream)
77{
78 snd_rawmidi_runtime_t *runtime;
79 seq_midisynth_t *msynth;
80 snd_seq_event_t ev;
81 char buf[16], *pbuf;
82 long res, count;
83
84 if (substream == NULL)
85 return;
86 runtime = substream->runtime;
87 msynth = (seq_midisynth_t *) runtime->private_data;
88 if (msynth == NULL)
89 return;
90 memset(&ev, 0, sizeof(ev));
91 while (runtime->avail > 0) {
92 res = snd_rawmidi_kernel_read(substream, buf, sizeof(buf));
93 if (res <= 0)
94 continue;
95 if (msynth->parser == NULL)
96 continue;
97 pbuf = buf;
98 while (res > 0) {
99 count = snd_midi_event_encode(msynth->parser, pbuf, res, &ev);
100 if (count < 0)
101 break;
102 pbuf += count;
103 res -= count;
104 if (ev.type != SNDRV_SEQ_EVENT_NONE) {
105 ev.source.port = msynth->seq_port;
106 ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
107 snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0);
108 /* clear event and reset header */
109 memset(&ev, 0, sizeof(ev));
110 }
111 }
112 }
113}
114
115static int dump_midi(snd_rawmidi_substream_t *substream, const char *buf, int count)
116{
117 snd_rawmidi_runtime_t *runtime;
118 int tmp;
119
120 snd_assert(substream != NULL || buf != NULL, return -EINVAL);
121 runtime = substream->runtime;
122 if ((tmp = runtime->avail) < count) {
123 snd_printd("warning, output event was lost (count = %i, available = %i)\n", count, tmp);
124 return -ENOMEM;
125 }
126 if (snd_rawmidi_kernel_write(substream, buf, count) < count)
127 return -EINVAL;
128 return 0;
129}
130
131static int event_process_midi(snd_seq_event_t * ev, int direct,
132 void *private_data, int atomic, int hop)
133{
134 seq_midisynth_t *msynth = (seq_midisynth_t *) private_data;
135 unsigned char msg[10]; /* buffer for constructing midi messages */
136 snd_rawmidi_substream_t *substream;
137 int res;
138
139 snd_assert(msynth != NULL, return -EINVAL);
140 substream = msynth->output_rfile.output;
141 if (substream == NULL)
142 return -ENODEV;
143 if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */
144 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
145 /* invalid event */
146 snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
147 return 0;
148 }
149 res = snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
150 snd_midi_event_reset_decode(msynth->parser);
151 if (res < 0)
152 return res;
153 } else {
154 if (msynth->parser == NULL)
155 return -EIO;
156 res = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
157 if (res < 0)
158 return res;
159 if ((res = dump_midi(substream, msg, res)) < 0) {
160 snd_midi_event_reset_decode(msynth->parser);
161 return res;
162 }
163 }
164 return 0;
165}
166
167
168static int snd_seq_midisynth_new(seq_midisynth_t *msynth,
169 snd_card_t *card,
170 int device,
171 int subdevice)
172{
173 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &msynth->parser) < 0)
174 return -ENOMEM;
175 msynth->card = card;
176 msynth->device = device;
177 msynth->subdevice = subdevice;
178 return 0;
179}
180
181/* open associated midi device for input */
182static int midisynth_subscribe(void *private_data, snd_seq_port_subscribe_t *info)
183{
184 int err;
185 seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
186 snd_rawmidi_runtime_t *runtime;
187 snd_rawmidi_params_t params;
188
189 /* open midi port */
190 if ((err = snd_rawmidi_kernel_open(msynth->card->number, msynth->device, msynth->subdevice, SNDRV_RAWMIDI_LFLG_INPUT, &msynth->input_rfile)) < 0) {
191 snd_printd("midi input open failed!!!\n");
192 return err;
193 }
194 runtime = msynth->input_rfile.input->runtime;
195 memset(&params, 0, sizeof(params));
196 params.avail_min = 1;
197 params.buffer_size = input_buffer_size;
198 if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, &params)) < 0) {
199 snd_rawmidi_kernel_release(&msynth->input_rfile);
200 return err;
201 }
202 snd_midi_event_reset_encode(msynth->parser);
203 runtime->event = snd_midi_input_event;
204 runtime->private_data = msynth;
205 snd_rawmidi_kernel_read(msynth->input_rfile.input, NULL, 0);
206 return 0;
207}
208
209/* close associated midi device for input */
210static int midisynth_unsubscribe(void *private_data, snd_seq_port_subscribe_t *info)
211{
212 int err;
213 seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
214
215 snd_assert(msynth->input_rfile.input != NULL, return -EINVAL);
216 err = snd_rawmidi_kernel_release(&msynth->input_rfile);
217 return err;
218}
219
220/* open associated midi device for output */
221static int midisynth_use(void *private_data, snd_seq_port_subscribe_t *info)
222{
223 int err;
224 seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
225 snd_rawmidi_params_t params;
226
227 /* open midi port */
228 if ((err = snd_rawmidi_kernel_open(msynth->card->number, msynth->device, msynth->subdevice, SNDRV_RAWMIDI_LFLG_OUTPUT, &msynth->output_rfile)) < 0) {
229 snd_printd("midi output open failed!!!\n");
230 return err;
231 }
232 memset(&params, 0, sizeof(params));
233 params.avail_min = 1;
234 params.buffer_size = output_buffer_size;
235 if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, &params)) < 0) {
236 snd_rawmidi_kernel_release(&msynth->output_rfile);
237 return err;
238 }
239 snd_midi_event_reset_decode(msynth->parser);
240 return 0;
241}
242
243/* close associated midi device for output */
244static int midisynth_unuse(void *private_data, snd_seq_port_subscribe_t *info)
245{
246 seq_midisynth_t *msynth = (seq_midisynth_t *)private_data;
247 unsigned char buf = 0xff; /* MIDI reset */
248
249 snd_assert(msynth->output_rfile.output != NULL, return -EINVAL);
250 /* sending single MIDI reset message to shut the device up */
251 snd_rawmidi_kernel_write(msynth->output_rfile.output, &buf, 1);
252 snd_rawmidi_drain_output(msynth->output_rfile.output);
253 return snd_rawmidi_kernel_release(&msynth->output_rfile);
254}
255
256/* delete given midi synth port */
257static void snd_seq_midisynth_delete(seq_midisynth_t *msynth)
258{
259 if (msynth == NULL)
260 return;
261
262 if (msynth->seq_client > 0) {
263 /* delete port */
264 snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
265 }
266
267 if (msynth->parser)
268 snd_midi_event_free(msynth->parser);
269}
270
271/* set our client name */
272static int set_client_name(seq_midisynth_client_t *client, snd_card_t *card,
273 snd_rawmidi_info_t *rmidi)
274{
275 snd_seq_client_info_t cinfo;
276 const char *name;
277
278 memset(&cinfo, 0, sizeof(cinfo));
279 cinfo.client = client->seq_client;
280 cinfo.type = KERNEL_CLIENT;
281 name = rmidi->name[0] ? (const char *)rmidi->name : "External MIDI";
282 strlcpy(cinfo.name, name, sizeof(cinfo.name));
283 return snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo);
284}
285
286/* register new midi synth port */
287static int
288snd_seq_midisynth_register_port(snd_seq_device_t *dev)
289{
290 seq_midisynth_client_t *client;
291 seq_midisynth_t *msynth, *ms;
292 snd_seq_port_info_t *port;
293 snd_rawmidi_info_t *info;
294 int newclient = 0;
295 unsigned int p, ports;
296 snd_seq_client_callback_t callbacks;
297 snd_seq_port_callback_t pcallbacks;
298 snd_card_t *card = dev->card;
299 int device = dev->device;
300 unsigned int input_count = 0, output_count = 0;
301
302 snd_assert(card != NULL && device >= 0 && device < SNDRV_RAWMIDI_DEVICES, return -EINVAL);
303 info = kmalloc(sizeof(*info), GFP_KERNEL);
304 if (! info)
305 return -ENOMEM;
306 info->device = device;
307 info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
308 info->subdevice = 0;
309 if (snd_rawmidi_info_select(card, info) >= 0)
310 output_count = info->subdevices_count;
311 info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
312 if (snd_rawmidi_info_select(card, info) >= 0) {
313 input_count = info->subdevices_count;
314 }
315 ports = output_count;
316 if (ports < input_count)
317 ports = input_count;
318 if (ports == 0) {
319 kfree(info);
320 return -ENODEV;
321 }
322 if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
323 ports = 256 / SNDRV_RAWMIDI_DEVICES;
324
325 down(&register_mutex);
326 client = synths[card->number];
327 if (client == NULL) {
328 newclient = 1;
329 client = kcalloc(1, sizeof(*client), GFP_KERNEL);
330 if (client == NULL) {
331 up(&register_mutex);
332 kfree(info);
333 return -ENOMEM;
334 }
335 memset(&callbacks, 0, sizeof(callbacks));
336 callbacks.private_data = client;
337 callbacks.allow_input = callbacks.allow_output = 1;
338 client->seq_client = snd_seq_create_kernel_client(card, 0, &callbacks);
339 if (client->seq_client < 0) {
340 kfree(client);
341 up(&register_mutex);
342 kfree(info);
343 return -ENOMEM;
344 }
345 set_client_name(client, card, info);
346 } else if (device == 0)
347 set_client_name(client, card, info); /* use the first device's name */
348
349 msynth = kcalloc(ports, sizeof(seq_midisynth_t), GFP_KERNEL);
350 port = kmalloc(sizeof(*port), GFP_KERNEL);
351 if (msynth == NULL || port == NULL)
352 goto __nomem;
353
354 for (p = 0; p < ports; p++) {
355 ms = &msynth[p];
356
357 if (snd_seq_midisynth_new(ms, card, device, p) < 0)
358 goto __nomem;
359
360 /* declare port */
361 memset(port, 0, sizeof(*port));
362 port->addr.client = client->seq_client;
363 port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
364 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
365 memset(info, 0, sizeof(*info));
366 info->device = device;
367 if (p < output_count)
368 info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
369 else
370 info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
371 info->subdevice = p;
372 if (snd_rawmidi_info_select(card, info) >= 0)
373 strcpy(port->name, info->subname);
374 if (! port->name[0]) {
375 if (info->name[0]) {
376 if (ports > 1)
377 snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p);
378 else
379 snprintf(port->name, sizeof(port->name), "%s", info->name);
380 } else {
381 /* last resort */
382 if (ports > 1)
383 sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p);
384 else
385 sprintf(port->name, "MIDI %d-%d", card->number, device);
386 }
387 }
388 if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
389 port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
390 if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
391 port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
392 if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
393 info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
394 port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
395 port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
396 port->midi_channels = 16;
397 memset(&pcallbacks, 0, sizeof(pcallbacks));
398 pcallbacks.owner = THIS_MODULE;
399 pcallbacks.private_data = ms;
400 pcallbacks.subscribe = midisynth_subscribe;
401 pcallbacks.unsubscribe = midisynth_unsubscribe;
402 pcallbacks.use = midisynth_use;
403 pcallbacks.unuse = midisynth_unuse;
404 pcallbacks.event_input = event_process_midi;
405 port->kernel = &pcallbacks;
406 if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
407 goto __nomem;
408 ms->seq_client = client->seq_client;
409 ms->seq_port = port->addr.port;
410 }
411 client->ports_per_device[device] = ports;
412 client->ports[device] = msynth;
413 client->num_ports++;
414 if (newclient)
415 synths[card->number] = client;
416 up(&register_mutex);
417 return 0; /* success */
418
419 __nomem:
420 if (msynth != NULL) {
421 for (p = 0; p < ports; p++)
422 snd_seq_midisynth_delete(&msynth[p]);
423 kfree(msynth);
424 }
425 if (newclient) {
426 snd_seq_delete_kernel_client(client->seq_client);
427 kfree(client);
428 }
429 kfree(info);
430 kfree(port);
431 up(&register_mutex);
432 return -ENOMEM;
433}
434
435/* release midi synth port */
436static int
437snd_seq_midisynth_unregister_port(snd_seq_device_t *dev)
438{
439 seq_midisynth_client_t *client;
440 seq_midisynth_t *msynth;
441 snd_card_t *card = dev->card;
442 int device = dev->device, p, ports;
443
444 down(&register_mutex);
445 client = synths[card->number];
446 if (client == NULL || client->ports[device] == NULL) {
447 up(&register_mutex);
448 return -ENODEV;
449 }
450 ports = client->ports_per_device[device];
451 client->ports_per_device[device] = 0;
452 msynth = client->ports[device];
453 client->ports[device] = NULL;
454 snd_runtime_check(msynth != NULL || ports <= 0, goto __skip);
455 for (p = 0; p < ports; p++)
456 snd_seq_midisynth_delete(&msynth[p]);
457 kfree(msynth);
458 __skip:
459 client->num_ports--;
460 if (client->num_ports <= 0) {
461 snd_seq_delete_kernel_client(client->seq_client);
462 synths[card->number] = NULL;
463 kfree(client);
464 }
465 up(&register_mutex);
466 return 0;
467}
468
469
470static int __init alsa_seq_midi_init(void)
471{
472 static snd_seq_dev_ops_t ops = {
473 snd_seq_midisynth_register_port,
474 snd_seq_midisynth_unregister_port,
475 };
476 memset(&synths, 0, sizeof(synths));
477 snd_seq_autoload_lock();
478 snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0);
479 snd_seq_autoload_unlock();
480 return 0;
481}
482
483static void __exit alsa_seq_midi_exit(void)
484{
485 snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH);
486}
487
488module_init(alsa_seq_midi_init)
489module_exit(alsa_seq_midi_exit)
diff --git a/sound/core/seq/seq_midi_emul.c b/sound/core/seq/seq_midi_emul.c
new file mode 100644
index 000000000000..35fe8a7e34bf
--- /dev/null
+++ b/sound/core/seq/seq_midi_emul.c
@@ -0,0 +1,735 @@
1/*
2 * GM/GS/XG midi module.
3 *
4 * Copyright (C) 1999 Steve Ratcliffe
5 *
6 * Based on awe_wave.c by Takashi Iwai
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23/*
24 * This module is used to keep track of the current midi state.
25 * It can be used for drivers that are required to emulate midi when
26 * the hardware doesn't.
27 *
28 * It was written for a AWE64 driver, but there should be no AWE specific
29 * code in here. If there is it should be reported as a bug.
30 */
31
32#include <sound/driver.h>
33#include <linux/init.h>
34#include <linux/slab.h>
35#include <linux/string.h>
36#include <sound/core.h>
37#include <sound/seq_kernel.h>
38#include <sound/seq_midi_emul.h>
39#include <sound/initval.h>
40#include <sound/asoundef.h>
41
42MODULE_AUTHOR("Takashi Iwai / Steve Ratcliffe");
43MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI emulation.");
44MODULE_LICENSE("GPL");
45
46/* Prototypes for static functions */
47static void note_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, int note, int vel);
48static void do_control(snd_midi_op_t *ops, void *private,
49 snd_midi_channel_set_t *chset, snd_midi_channel_t *chan,
50 int control, int value);
51static void rpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset);
52static void nrpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, snd_midi_channel_set_t *chset);
53static void sysex(snd_midi_op_t *ops, void *private, unsigned char *sysex, int len, snd_midi_channel_set_t *chset);
54static void all_sounds_off(snd_midi_op_t *ops, void *private, snd_midi_channel_t *chan);
55static void all_notes_off(snd_midi_op_t *ops, void *private, snd_midi_channel_t *chan);
56static void snd_midi_reset_controllers(snd_midi_channel_t *chan);
57static void reset_all_channels(snd_midi_channel_set_t *chset);
58
59
60/*
61 * Process an event in a driver independent way. This means dealing
62 * with RPN, NRPN, SysEx etc that are defined for common midi applications
63 * such as GM, GS and XG.
64 * There modes that this module will run in are:
65 * Generic MIDI - no interpretation at all, it will just save current values
66 * of controlers etc.
67 * GM - You can use all gm_ prefixed elements of chan. Controls, RPN, NRPN,
68 * SysEx will be interpreded as defined in General Midi.
69 * GS - You can use all gs_ prefixed elements of chan. Codes for GS will be
70 * interpreted.
71 * XG - You can use all xg_ prefixed elements of chan. Codes for XG will
72 * be interpreted.
73 */
74void
75snd_midi_process_event(snd_midi_op_t *ops,
76 snd_seq_event_t *ev, snd_midi_channel_set_t *chanset)
77{
78 snd_midi_channel_t *chan;
79 void *drv;
80 int dest_channel = 0;
81
82 if (ev == NULL || chanset == NULL) {
83 snd_printd("ev or chanbase NULL (snd_midi_process_event)\n");
84 return;
85 }
86 if (chanset->channels == NULL)
87 return;
88
89 if (snd_seq_ev_is_channel_type(ev)) {
90 dest_channel = ev->data.note.channel;
91 if (dest_channel >= chanset->max_channels) {
92 snd_printd("dest channel is %d, max is %d\n", dest_channel, chanset->max_channels);
93 return;
94 }
95 }
96
97 chan = chanset->channels + dest_channel;
98 drv = chanset->private_data;
99
100 /* EVENT_NOTE should be processed before queued */
101 if (ev->type == SNDRV_SEQ_EVENT_NOTE)
102 return;
103
104 /* Make sure that we don't have a note on that should really be
105 * a note off */
106 if (ev->type == SNDRV_SEQ_EVENT_NOTEON && ev->data.note.velocity == 0)
107 ev->type = SNDRV_SEQ_EVENT_NOTEOFF;
108
109 /* Make sure the note is within array range */
110 if (ev->type == SNDRV_SEQ_EVENT_NOTEON ||
111 ev->type == SNDRV_SEQ_EVENT_NOTEOFF ||
112 ev->type == SNDRV_SEQ_EVENT_KEYPRESS) {
113 if (ev->data.note.note >= 128)
114 return;
115 }
116
117 switch (ev->type) {
118 case SNDRV_SEQ_EVENT_NOTEON:
119 if (chan->note[ev->data.note.note] & SNDRV_MIDI_NOTE_ON) {
120 if (ops->note_off)
121 ops->note_off(drv, ev->data.note.note, 0, chan);
122 }
123 chan->note[ev->data.note.note] = SNDRV_MIDI_NOTE_ON;
124 if (ops->note_on)
125 ops->note_on(drv, ev->data.note.note, ev->data.note.velocity, chan);
126 break;
127 case SNDRV_SEQ_EVENT_NOTEOFF:
128 if (! (chan->note[ev->data.note.note] & SNDRV_MIDI_NOTE_ON))
129 break;
130 if (ops->note_off)
131 note_off(ops, drv, chan, ev->data.note.note, ev->data.note.velocity);
132 break;
133 case SNDRV_SEQ_EVENT_KEYPRESS:
134 if (ops->key_press)
135 ops->key_press(drv, ev->data.note.note, ev->data.note.velocity, chan);
136 break;
137 case SNDRV_SEQ_EVENT_CONTROLLER:
138 do_control(ops, drv, chanset, chan,
139 ev->data.control.param, ev->data.control.value);
140 break;
141 case SNDRV_SEQ_EVENT_PGMCHANGE:
142 chan->midi_program = ev->data.control.value;
143 break;
144 case SNDRV_SEQ_EVENT_PITCHBEND:
145 chan->midi_pitchbend = ev->data.control.value;
146 if (ops->control)
147 ops->control(drv, MIDI_CTL_PITCHBEND, chan);
148 break;
149 case SNDRV_SEQ_EVENT_CHANPRESS:
150 chan->midi_pressure = ev->data.control.value;
151 if (ops->control)
152 ops->control(drv, MIDI_CTL_CHAN_PRESSURE, chan);
153 break;
154 case SNDRV_SEQ_EVENT_CONTROL14:
155 /* Best guess is that this is any of the 14 bit controller values */
156 if (ev->data.control.param < 32) {
157 /* set low part first */
158 chan->control[ev->data.control.param + 32] =
159 ev->data.control.value & 0x7f;
160 do_control(ops, drv, chanset, chan,
161 ev->data.control.param,
162 ((ev->data.control.value>>7) & 0x7f));
163 } else
164 do_control(ops, drv, chanset, chan,
165 ev->data.control.param,
166 ev->data.control.value);
167 break;
168 case SNDRV_SEQ_EVENT_NONREGPARAM:
169 /* Break it back into its controler values */
170 chan->param_type = SNDRV_MIDI_PARAM_TYPE_NONREGISTERED;
171 chan->control[MIDI_CTL_MSB_DATA_ENTRY]
172 = (ev->data.control.value >> 7) & 0x7f;
173 chan->control[MIDI_CTL_LSB_DATA_ENTRY]
174 = ev->data.control.value & 0x7f;
175 chan->control[MIDI_CTL_NONREG_PARM_NUM_MSB]
176 = (ev->data.control.param >> 7) & 0x7f;
177 chan->control[MIDI_CTL_NONREG_PARM_NUM_LSB]
178 = ev->data.control.param & 0x7f;
179 nrpn(ops, drv, chan, chanset);
180 break;
181 case SNDRV_SEQ_EVENT_REGPARAM:
182 /* Break it back into its controler values */
183 chan->param_type = SNDRV_MIDI_PARAM_TYPE_REGISTERED;
184 chan->control[MIDI_CTL_MSB_DATA_ENTRY]
185 = (ev->data.control.value >> 7) & 0x7f;
186 chan->control[MIDI_CTL_LSB_DATA_ENTRY]
187 = ev->data.control.value & 0x7f;
188 chan->control[MIDI_CTL_REGIST_PARM_NUM_MSB]
189 = (ev->data.control.param >> 7) & 0x7f;
190 chan->control[MIDI_CTL_REGIST_PARM_NUM_LSB]
191 = ev->data.control.param & 0x7f;
192 rpn(ops, drv, chan, chanset);
193 break;
194 case SNDRV_SEQ_EVENT_SYSEX:
195 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) == SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
196 unsigned char sysexbuf[64];
197 int len;
198 len = snd_seq_expand_var_event(ev, sizeof(sysexbuf), sysexbuf, 1, 0);
199 if (len > 0)
200 sysex(ops, drv, sysexbuf, len, chanset);
201 }
202 break;
203 case SNDRV_SEQ_EVENT_SONGPOS:
204 case SNDRV_SEQ_EVENT_SONGSEL:
205 case SNDRV_SEQ_EVENT_CLOCK:
206 case SNDRV_SEQ_EVENT_START:
207 case SNDRV_SEQ_EVENT_CONTINUE:
208 case SNDRV_SEQ_EVENT_STOP:
209 case SNDRV_SEQ_EVENT_QFRAME:
210 case SNDRV_SEQ_EVENT_TEMPO:
211 case SNDRV_SEQ_EVENT_TIMESIGN:
212 case SNDRV_SEQ_EVENT_KEYSIGN:
213 goto not_yet;
214 case SNDRV_SEQ_EVENT_SENSING:
215 break;
216 case SNDRV_SEQ_EVENT_CLIENT_START:
217 case SNDRV_SEQ_EVENT_CLIENT_EXIT:
218 case SNDRV_SEQ_EVENT_CLIENT_CHANGE:
219 case SNDRV_SEQ_EVENT_PORT_START:
220 case SNDRV_SEQ_EVENT_PORT_EXIT:
221 case SNDRV_SEQ_EVENT_PORT_CHANGE:
222 case SNDRV_SEQ_EVENT_SAMPLE:
223 case SNDRV_SEQ_EVENT_SAMPLE_START:
224 case SNDRV_SEQ_EVENT_SAMPLE_STOP:
225 case SNDRV_SEQ_EVENT_SAMPLE_FREQ:
226 case SNDRV_SEQ_EVENT_SAMPLE_VOLUME:
227 case SNDRV_SEQ_EVENT_SAMPLE_LOOP:
228 case SNDRV_SEQ_EVENT_SAMPLE_POSITION:
229 case SNDRV_SEQ_EVENT_ECHO:
230 not_yet:
231 default:
232 /*snd_printd("Unimplemented event %d\n", ev->type);*/
233 break;
234 }
235}
236
237
238/*
239 * release note
240 */
241static void
242note_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan, int note, int vel)
243{
244 if (chan->gm_hold) {
245 /* Hold this note until pedal is turned off */
246 chan->note[note] |= SNDRV_MIDI_NOTE_RELEASED;
247 } else if (chan->note[note] & SNDRV_MIDI_NOTE_SOSTENUTO) {
248 /* Mark this note as release; it will be turned off when sostenuto
249 * is turned off */
250 chan->note[note] |= SNDRV_MIDI_NOTE_RELEASED;
251 } else {
252 chan->note[note] = 0;
253 if (ops->note_off)
254 ops->note_off(drv, note, vel, chan);
255 }
256}
257
258/*
259 * Do all driver independent operations for this controler and pass
260 * events that need to take place immediately to the driver.
261 */
262static void
263do_control(snd_midi_op_t *ops, void *drv, snd_midi_channel_set_t *chset,
264 snd_midi_channel_t *chan, int control, int value)
265{
266 int i;
267
268 /* Switches */
269 if ((control >=64 && control <=69) || (control >= 80 && control <= 83)) {
270 /* These are all switches; either off or on so set to 0 or 127 */
271 value = (value >= 64)? 127: 0;
272 }
273 chan->control[control] = value;
274
275 switch (control) {
276 case MIDI_CTL_SUSTAIN:
277 if (value == 0) {
278 /* Sustain has been released, turn off held notes */
279 for (i = 0; i < 128; i++) {
280 if (chan->note[i] & SNDRV_MIDI_NOTE_RELEASED) {
281 chan->note[i] = SNDRV_MIDI_NOTE_OFF;
282 if (ops->note_off)
283 ops->note_off(drv, i, 0, chan);
284 }
285 }
286 }
287 break;
288 case MIDI_CTL_PORTAMENTO:
289 break;
290 case MIDI_CTL_SOSTENUTO:
291 if (value) {
292 /* Mark each note that is currently held down */
293 for (i = 0; i < 128; i++) {
294 if (chan->note[i] & SNDRV_MIDI_NOTE_ON)
295 chan->note[i] |= SNDRV_MIDI_NOTE_SOSTENUTO;
296 }
297 } else {
298 /* release all notes that were held */
299 for (i = 0; i < 128; i++) {
300 if (chan->note[i] & SNDRV_MIDI_NOTE_SOSTENUTO) {
301 chan->note[i] &= ~SNDRV_MIDI_NOTE_SOSTENUTO;
302 if (chan->note[i] & SNDRV_MIDI_NOTE_RELEASED) {
303 chan->note[i] = SNDRV_MIDI_NOTE_OFF;
304 if (ops->note_off)
305 ops->note_off(drv, i, 0, chan);
306 }
307 }
308 }
309 }
310 break;
311 case MIDI_CTL_MSB_DATA_ENTRY:
312 chan->control[MIDI_CTL_LSB_DATA_ENTRY] = 0;
313 /* go through here */
314 case MIDI_CTL_LSB_DATA_ENTRY:
315 if (chan->param_type == SNDRV_MIDI_PARAM_TYPE_REGISTERED)
316 rpn(ops, drv, chan, chset);
317 else
318 nrpn(ops, drv, chan, chset);
319 break;
320 case MIDI_CTL_REGIST_PARM_NUM_LSB:
321 case MIDI_CTL_REGIST_PARM_NUM_MSB:
322 chan->param_type = SNDRV_MIDI_PARAM_TYPE_REGISTERED;
323 break;
324 case MIDI_CTL_NONREG_PARM_NUM_LSB:
325 case MIDI_CTL_NONREG_PARM_NUM_MSB:
326 chan->param_type = SNDRV_MIDI_PARAM_TYPE_NONREGISTERED;
327 break;
328
329 case MIDI_CTL_ALL_SOUNDS_OFF:
330 all_sounds_off(ops, drv, chan);
331 break;
332
333 case MIDI_CTL_ALL_NOTES_OFF:
334 all_notes_off(ops, drv, chan);
335 break;
336
337 case MIDI_CTL_MSB_BANK:
338 if (chset->midi_mode == SNDRV_MIDI_MODE_XG) {
339 if (value == 127)
340 chan->drum_channel = 1;
341 else
342 chan->drum_channel = 0;
343 }
344 break;
345 case MIDI_CTL_LSB_BANK:
346 break;
347
348 case MIDI_CTL_RESET_CONTROLLERS:
349 snd_midi_reset_controllers(chan);
350 break;
351
352 case MIDI_CTL_SOFT_PEDAL:
353 case MIDI_CTL_LEGATO_FOOTSWITCH:
354 case MIDI_CTL_HOLD2:
355 case MIDI_CTL_SC1_SOUND_VARIATION:
356 case MIDI_CTL_SC2_TIMBRE:
357 case MIDI_CTL_SC3_RELEASE_TIME:
358 case MIDI_CTL_SC4_ATTACK_TIME:
359 case MIDI_CTL_SC5_BRIGHTNESS:
360 case MIDI_CTL_E1_REVERB_DEPTH:
361 case MIDI_CTL_E2_TREMOLO_DEPTH:
362 case MIDI_CTL_E3_CHORUS_DEPTH:
363 case MIDI_CTL_E4_DETUNE_DEPTH:
364 case MIDI_CTL_E5_PHASER_DEPTH:
365 goto notyet;
366 notyet:
367 default:
368 if (ops->control)
369 ops->control(drv, control, chan);
370 break;
371 }
372}
373
374
375/*
376 * initialize the MIDI status
377 */
378void
379snd_midi_channel_set_clear(snd_midi_channel_set_t *chset)
380{
381 int i;
382
383 chset->midi_mode = SNDRV_MIDI_MODE_GM;
384 chset->gs_master_volume = 127;
385
386 for (i = 0; i < chset->max_channels; i++) {
387 snd_midi_channel_t *chan = chset->channels + i;
388 memset(chan->note, 0, sizeof(chan->note));
389
390 chan->midi_aftertouch = 0;
391 chan->midi_pressure = 0;
392 chan->midi_program = 0;
393 chan->midi_pitchbend = 0;
394 snd_midi_reset_controllers(chan);
395 chan->gm_rpn_pitch_bend_range = 256; /* 2 semitones */
396 chan->gm_rpn_fine_tuning = 0;
397 chan->gm_rpn_coarse_tuning = 0;
398
399 if (i == 9)
400 chan->drum_channel = 1;
401 else
402 chan->drum_channel = 0;
403 }
404}
405
406/*
407 * Process a rpn message.
408 */
409static void
410rpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan,
411 snd_midi_channel_set_t *chset)
412{
413 int type;
414 int val;
415
416 if (chset->midi_mode != SNDRV_MIDI_MODE_NONE) {
417 type = (chan->control[MIDI_CTL_REGIST_PARM_NUM_MSB] << 8) |
418 chan->control[MIDI_CTL_REGIST_PARM_NUM_LSB];
419 val = (chan->control[MIDI_CTL_MSB_DATA_ENTRY] << 7) |
420 chan->control[MIDI_CTL_LSB_DATA_ENTRY];
421
422 switch (type) {
423 case 0x0000: /* Pitch bend sensitivity */
424 /* MSB only / 1 semitone per 128 */
425 chan->gm_rpn_pitch_bend_range = val;
426 break;
427
428 case 0x0001: /* fine tuning: */
429 /* MSB/LSB, 8192=center, 100/8192 cent step */
430 chan->gm_rpn_fine_tuning = val - 8192;
431 break;
432
433 case 0x0002: /* coarse tuning */
434 /* MSB only / 8192=center, 1 semitone per 128 */
435 chan->gm_rpn_coarse_tuning = val - 8192;
436 break;
437
438 case 0x7F7F: /* "lock-in" RPN */
439 /* ignored */
440 break;
441 }
442 }
443 /* should call nrpn or rpn callback here.. */
444}
445
446/*
447 * Process an nrpn message.
448 */
449static void
450nrpn(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan,
451 snd_midi_channel_set_t *chset)
452{
453 /* parse XG NRPNs here if possible */
454 if (ops->nrpn)
455 ops->nrpn(drv, chan, chset);
456}
457
458
459/*
460 * convert channel parameter in GS sysex
461 */
462static int
463get_channel(unsigned char cmd)
464{
465 int p = cmd & 0x0f;
466 if (p == 0)
467 p = 9;
468 else if (p < 10)
469 p--;
470 return p;
471}
472
473
474/*
475 * Process a sysex message.
476 */
477static void
478sysex(snd_midi_op_t *ops, void *private, unsigned char *buf, int len, snd_midi_channel_set_t *chset)
479{
480 /* GM on */
481 static unsigned char gm_on_macro[] = {
482 0x7e,0x7f,0x09,0x01,
483 };
484 /* XG on */
485 static unsigned char xg_on_macro[] = {
486 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
487 };
488 /* GS prefix
489 * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
490 * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
491 * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
492 * master vol: XX=0x00, YY=0x04, ZZ=0-127
493 */
494 static unsigned char gs_pfx_macro[] = {
495 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
496 };
497
498 int parsed = SNDRV_MIDI_SYSEX_NOT_PARSED;
499
500 if (len <= 0 || buf[0] != 0xf0)
501 return;
502 /* skip first byte */
503 buf++;
504 len--;
505
506 /* GM on */
507 if (len >= (int)sizeof(gm_on_macro) &&
508 memcmp(buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
509 if (chset->midi_mode != SNDRV_MIDI_MODE_GS &&
510 chset->midi_mode != SNDRV_MIDI_MODE_XG) {
511 chset->midi_mode = SNDRV_MIDI_MODE_GM;
512 reset_all_channels(chset);
513 parsed = SNDRV_MIDI_SYSEX_GM_ON;
514 }
515 }
516
517 /* GS macros */
518 else if (len >= 8 &&
519 memcmp(buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
520 if (chset->midi_mode != SNDRV_MIDI_MODE_GS &&
521 chset->midi_mode != SNDRV_MIDI_MODE_XG)
522 chset->midi_mode = SNDRV_MIDI_MODE_GS;
523
524 if (buf[5] == 0x00 && buf[6] == 0x7f && buf[7] == 0x00) {
525 /* GS reset */
526 parsed = SNDRV_MIDI_SYSEX_GS_RESET;
527 reset_all_channels(chset);
528 }
529
530 else if ((buf[5] & 0xf0) == 0x10 && buf[6] == 0x15) {
531 /* drum pattern */
532 int p = get_channel(buf[5]);
533 if (p < chset->max_channels) {
534 parsed = SNDRV_MIDI_SYSEX_GS_DRUM_CHANNEL;
535 if (buf[7])
536 chset->channels[p].drum_channel = 1;
537 else
538 chset->channels[p].drum_channel = 0;
539 }
540
541 } else if ((buf[5] & 0xf0) == 0x10 && buf[6] == 0x21) {
542 /* program */
543 int p = get_channel(buf[5]);
544 if (p < chset->max_channels &&
545 ! chset->channels[p].drum_channel) {
546 parsed = SNDRV_MIDI_SYSEX_GS_DRUM_CHANNEL;
547 chset->channels[p].midi_program = buf[7];
548 }
549
550 } else if (buf[5] == 0x01 && buf[6] == 0x30) {
551 /* reverb mode */
552 parsed = SNDRV_MIDI_SYSEX_GS_REVERB_MODE;
553 chset->gs_reverb_mode = buf[7];
554
555 } else if (buf[5] == 0x01 && buf[6] == 0x38) {
556 /* chorus mode */
557 parsed = SNDRV_MIDI_SYSEX_GS_CHORUS_MODE;
558 chset->gs_chorus_mode = buf[7];
559
560 } else if (buf[5] == 0x00 && buf[6] == 0x04) {
561 /* master volume */
562 parsed = SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME;
563 chset->gs_master_volume = buf[7];
564
565 }
566 }
567
568 /* XG on */
569 else if (len >= (int)sizeof(xg_on_macro) &&
570 memcmp(buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
571 int i;
572 chset->midi_mode = SNDRV_MIDI_MODE_XG;
573 parsed = SNDRV_MIDI_SYSEX_XG_ON;
574 /* reset CC#0 for drums */
575 for (i = 0; i < chset->max_channels; i++) {
576 if (chset->channels[i].drum_channel)
577 chset->channels[i].control[MIDI_CTL_MSB_BANK] = 127;
578 else
579 chset->channels[i].control[MIDI_CTL_MSB_BANK] = 0;
580 }
581 }
582
583 if (ops->sysex)
584 ops->sysex(private, buf - 1, len + 1, parsed, chset);
585}
586
587/*
588 * all sound off
589 */
590static void
591all_sounds_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan)
592{
593 int n;
594
595 if (! ops->note_terminate)
596 return;
597 for (n = 0; n < 128; n++) {
598 if (chan->note[n]) {
599 ops->note_terminate(drv, n, chan);
600 chan->note[n] = 0;
601 }
602 }
603}
604
605/*
606 * all notes off
607 */
608static void
609all_notes_off(snd_midi_op_t *ops, void *drv, snd_midi_channel_t *chan)
610{
611 int n;
612
613 if (! ops->note_off)
614 return;
615 for (n = 0; n < 128; n++) {
616 if (chan->note[n] == SNDRV_MIDI_NOTE_ON)
617 note_off(ops, drv, chan, n, 0);
618 }
619}
620
621/*
622 * Initialise a single midi channel control block.
623 */
624static void snd_midi_channel_init(snd_midi_channel_t *p, int n)
625{
626 if (p == NULL)
627 return;
628
629 memset(p, 0, sizeof(snd_midi_channel_t));
630 p->private = NULL;
631 p->number = n;
632
633 snd_midi_reset_controllers(p);
634 p->gm_rpn_pitch_bend_range = 256; /* 2 semitones */
635 p->gm_rpn_fine_tuning = 0;
636 p->gm_rpn_coarse_tuning = 0;
637
638 if (n == 9)
639 p->drum_channel = 1; /* Default ch 10 as drums */
640}
641
642/*
643 * Allocate and initialise a set of midi channel control blocks.
644 */
645static snd_midi_channel_t *snd_midi_channel_init_set(int n)
646{
647 snd_midi_channel_t *chan;
648 int i;
649
650 chan = kmalloc(n * sizeof(snd_midi_channel_t), GFP_KERNEL);
651 if (chan) {
652 for (i = 0; i < n; i++)
653 snd_midi_channel_init(chan+i, i);
654 }
655
656 return chan;
657}
658
659/*
660 * reset all midi channels
661 */
662static void
663reset_all_channels(snd_midi_channel_set_t *chset)
664{
665 int ch;
666 for (ch = 0; ch < chset->max_channels; ch++) {
667 snd_midi_channel_t *chan = chset->channels + ch;
668 snd_midi_reset_controllers(chan);
669 chan->gm_rpn_pitch_bend_range = 256; /* 2 semitones */
670 chan->gm_rpn_fine_tuning = 0;
671 chan->gm_rpn_coarse_tuning = 0;
672
673 if (ch == 9)
674 chan->drum_channel = 1;
675 else
676 chan->drum_channel = 0;
677 }
678}
679
680
681/*
682 * Allocate and initialise a midi channel set.
683 */
684snd_midi_channel_set_t *snd_midi_channel_alloc_set(int n)
685{
686 snd_midi_channel_set_t *chset;
687
688 chset = kmalloc(sizeof(*chset), GFP_KERNEL);
689 if (chset) {
690 chset->channels = snd_midi_channel_init_set(n);
691 chset->private_data = NULL;
692 chset->max_channels = n;
693 }
694 return chset;
695}
696
697/*
698 * Reset the midi controllers on a particular channel to default values.
699 */
700static void snd_midi_reset_controllers(snd_midi_channel_t *chan)
701{
702 memset(chan->control, 0, sizeof(chan->control));
703 chan->gm_volume = 127;
704 chan->gm_expression = 127;
705 chan->gm_pan = 64;
706}
707
708
709/*
710 * Free a midi channel set.
711 */
712void snd_midi_channel_free_set(snd_midi_channel_set_t *chset)
713{
714 if (chset == NULL)
715 return;
716 kfree(chset->channels);
717 kfree(chset);
718}
719
720static int __init alsa_seq_midi_emul_init(void)
721{
722 return 0;
723}
724
725static void __exit alsa_seq_midi_emul_exit(void)
726{
727}
728
729module_init(alsa_seq_midi_emul_init)
730module_exit(alsa_seq_midi_emul_exit)
731
732EXPORT_SYMBOL(snd_midi_process_event);
733EXPORT_SYMBOL(snd_midi_channel_set_clear);
734EXPORT_SYMBOL(snd_midi_channel_alloc_set);
735EXPORT_SYMBOL(snd_midi_channel_free_set);
diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c
new file mode 100644
index 000000000000..21e569062bc3
--- /dev/null
+++ b/sound/core/seq/seq_midi_event.c
@@ -0,0 +1,539 @@
1/*
2 * MIDI byte <-> sequencer event coder
3 *
4 * Copyright (C) 1998,99 Takashi Iwai <tiwai@suse.de>,
5 * Jaroslav Kysela <perex@suse.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <sound/driver.h>
23#include <linux/slab.h>
24#include <linux/errno.h>
25#include <linux/string.h>
26#include <sound/core.h>
27#include <sound/seq_kernel.h>
28#include <sound/seq_midi_event.h>
29#include <sound/asoundef.h>
30
31MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@suse.cz>");
32MODULE_DESCRIPTION("MIDI byte <-> sequencer event coder");
33MODULE_LICENSE("GPL");
34
35/* queue type */
36/* from 0 to 7 are normal commands (note off, on, etc.) */
37#define ST_NOTEOFF 0
38#define ST_NOTEON 1
39#define ST_SPECIAL 8
40#define ST_SYSEX ST_SPECIAL
41/* from 8 to 15 are events for 0xf0-0xf7 */
42
43
44/* status event types */
45typedef void (*event_encode_t)(snd_midi_event_t *dev, snd_seq_event_t *ev);
46typedef void (*event_decode_t)(snd_seq_event_t *ev, unsigned char *buf);
47
48/*
49 * prototypes
50 */
51static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
52static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
53static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
54static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
55static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
56static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev);
57static void note_decode(snd_seq_event_t *ev, unsigned char *buf);
58static void one_param_decode(snd_seq_event_t *ev, unsigned char *buf);
59static void pitchbend_decode(snd_seq_event_t *ev, unsigned char *buf);
60static void two_param_decode(snd_seq_event_t *ev, unsigned char *buf);
61static void songpos_decode(snd_seq_event_t *ev, unsigned char *buf);
62
63/*
64 * event list
65 */
66static struct status_event_list_t {
67 int event;
68 int qlen;
69 event_encode_t encode;
70 event_decode_t decode;
71} status_event[] = {
72 /* 0x80 - 0xf0 */
73 {SNDRV_SEQ_EVENT_NOTEOFF, 2, note_event, note_decode},
74 {SNDRV_SEQ_EVENT_NOTEON, 2, note_event, note_decode},
75 {SNDRV_SEQ_EVENT_KEYPRESS, 2, note_event, note_decode},
76 {SNDRV_SEQ_EVENT_CONTROLLER, 2, two_param_ctrl_event, two_param_decode},
77 {SNDRV_SEQ_EVENT_PGMCHANGE, 1, one_param_ctrl_event, one_param_decode},
78 {SNDRV_SEQ_EVENT_CHANPRESS, 1, one_param_ctrl_event, one_param_decode},
79 {SNDRV_SEQ_EVENT_PITCHBEND, 2, pitchbend_ctrl_event, pitchbend_decode},
80 {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf0 */
81 /* 0xf0 - 0xff */
82 {SNDRV_SEQ_EVENT_SYSEX, 1, NULL, NULL}, /* sysex: 0xf0 */
83 {SNDRV_SEQ_EVENT_QFRAME, 1, one_param_event, one_param_decode}, /* 0xf1 */
84 {SNDRV_SEQ_EVENT_SONGPOS, 2, songpos_event, songpos_decode}, /* 0xf2 */
85 {SNDRV_SEQ_EVENT_SONGSEL, 1, one_param_event, one_param_decode}, /* 0xf3 */
86 {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf4 */
87 {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf5 */
88 {SNDRV_SEQ_EVENT_TUNE_REQUEST, 0, NULL, NULL}, /* 0xf6 */
89 {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf7 */
90 {SNDRV_SEQ_EVENT_CLOCK, 0, NULL, NULL}, /* 0xf8 */
91 {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xf9 */
92 {SNDRV_SEQ_EVENT_START, 0, NULL, NULL}, /* 0xfa */
93 {SNDRV_SEQ_EVENT_CONTINUE, 0, NULL, NULL}, /* 0xfb */
94 {SNDRV_SEQ_EVENT_STOP, 0, NULL, NULL}, /* 0xfc */
95 {SNDRV_SEQ_EVENT_NONE, 0, NULL, NULL}, /* 0xfd */
96 {SNDRV_SEQ_EVENT_SENSING, 0, NULL, NULL}, /* 0xfe */
97 {SNDRV_SEQ_EVENT_RESET, 0, NULL, NULL}, /* 0xff */
98};
99
100static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
101static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev);
102
103static struct extra_event_list_t {
104 int event;
105 int (*decode)(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev);
106} extra_event[] = {
107 {SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
108 {SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
109 {SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn},
110};
111
112/*
113 * new/delete record
114 */
115
116int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev)
117{
118 snd_midi_event_t *dev;
119
120 *rdev = NULL;
121 dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
122 if (dev == NULL)
123 return -ENOMEM;
124 if (bufsize > 0) {
125 dev->buf = kmalloc(bufsize, GFP_KERNEL);
126 if (dev->buf == NULL) {
127 kfree(dev);
128 return -ENOMEM;
129 }
130 }
131 dev->bufsize = bufsize;
132 dev->lastcmd = 0xff;
133 spin_lock_init(&dev->lock);
134 *rdev = dev;
135 return 0;
136}
137
138void snd_midi_event_free(snd_midi_event_t *dev)
139{
140 if (dev != NULL) {
141 kfree(dev->buf);
142 kfree(dev);
143 }
144}
145
146/*
147 * initialize record
148 */
149inline static void reset_encode(snd_midi_event_t *dev)
150{
151 dev->read = 0;
152 dev->qlen = 0;
153 dev->type = 0;
154}
155
156void snd_midi_event_reset_encode(snd_midi_event_t *dev)
157{
158 unsigned long flags;
159
160 spin_lock_irqsave(&dev->lock, flags);
161 reset_encode(dev);
162 spin_unlock_irqrestore(&dev->lock, flags);
163}
164
165void snd_midi_event_reset_decode(snd_midi_event_t *dev)
166{
167 unsigned long flags;
168
169 spin_lock_irqsave(&dev->lock, flags);
170 dev->lastcmd = 0xff;
171 spin_unlock_irqrestore(&dev->lock, flags);
172}
173
174void snd_midi_event_init(snd_midi_event_t *dev)
175{
176 snd_midi_event_reset_encode(dev);
177 snd_midi_event_reset_decode(dev);
178}
179
180void snd_midi_event_no_status(snd_midi_event_t *dev, int on)
181{
182 dev->nostat = on ? 1 : 0;
183}
184
185/*
186 * resize buffer
187 */
188int snd_midi_event_resize_buffer(snd_midi_event_t *dev, int bufsize)
189{
190 unsigned char *new_buf, *old_buf;
191 unsigned long flags;
192
193 if (bufsize == dev->bufsize)
194 return 0;
195 new_buf = kmalloc(bufsize, GFP_KERNEL);
196 if (new_buf == NULL)
197 return -ENOMEM;
198 spin_lock_irqsave(&dev->lock, flags);
199 old_buf = dev->buf;
200 dev->buf = new_buf;
201 dev->bufsize = bufsize;
202 reset_encode(dev);
203 spin_unlock_irqrestore(&dev->lock, flags);
204 kfree(old_buf);
205 return 0;
206}
207
208/*
209 * read bytes and encode to sequencer event if finished
210 * return the size of encoded bytes
211 */
212long snd_midi_event_encode(snd_midi_event_t *dev, unsigned char *buf, long count, snd_seq_event_t *ev)
213{
214 long result = 0;
215 int rc;
216
217 ev->type = SNDRV_SEQ_EVENT_NONE;
218
219 while (count-- > 0) {
220 rc = snd_midi_event_encode_byte(dev, *buf++, ev);
221 result++;
222 if (rc < 0)
223 return rc;
224 else if (rc > 0)
225 return result;
226 }
227
228 return result;
229}
230
231/*
232 * read one byte and encode to sequencer event:
233 * return 1 if MIDI bytes are encoded to an event
234 * 0 data is not finished
235 * negative for error
236 */
237int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev)
238{
239 int rc = 0;
240 unsigned long flags;
241
242 c &= 0xff;
243
244 if (c >= MIDI_CMD_COMMON_CLOCK) {
245 /* real-time event */
246 ev->type = status_event[ST_SPECIAL + c - 0xf0].event;
247 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
248 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
249 return 1;
250 }
251
252 spin_lock_irqsave(&dev->lock, flags);
253 if (dev->qlen > 0) {
254 /* rest of command */
255 dev->buf[dev->read++] = c;
256 if (dev->type != ST_SYSEX)
257 dev->qlen--;
258 } else {
259 /* new command */
260 dev->read = 1;
261 if (c & 0x80) {
262 dev->buf[0] = c;
263 if ((c & 0xf0) == 0xf0) /* special events */
264 dev->type = (c & 0x0f) + ST_SPECIAL;
265 else
266 dev->type = (c >> 4) & 0x07;
267 dev->qlen = status_event[dev->type].qlen;
268 } else {
269 /* process this byte as argument */
270 dev->buf[dev->read++] = c;
271 dev->qlen = status_event[dev->type].qlen - 1;
272 }
273 }
274 if (dev->qlen == 0) {
275 ev->type = status_event[dev->type].event;
276 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
277 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
278 if (status_event[dev->type].encode) /* set data values */
279 status_event[dev->type].encode(dev, ev);
280 rc = 1;
281 } else if (dev->type == ST_SYSEX) {
282 if (c == MIDI_CMD_COMMON_SYSEX_END ||
283 dev->read >= dev->bufsize) {
284 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
285 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_VARIABLE;
286 ev->type = SNDRV_SEQ_EVENT_SYSEX;
287 ev->data.ext.len = dev->read;
288 ev->data.ext.ptr = dev->buf;
289 if (c != MIDI_CMD_COMMON_SYSEX_END)
290 dev->read = 0; /* continue to parse */
291 else
292 reset_encode(dev); /* all parsed */
293 rc = 1;
294 }
295 }
296
297 spin_unlock_irqrestore(&dev->lock, flags);
298 return rc;
299}
300
301/* encode note event */
302static void note_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
303{
304 ev->data.note.channel = dev->buf[0] & 0x0f;
305 ev->data.note.note = dev->buf[1];
306 ev->data.note.velocity = dev->buf[2];
307}
308
309/* encode one parameter controls */
310static void one_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
311{
312 ev->data.control.channel = dev->buf[0] & 0x0f;
313 ev->data.control.value = dev->buf[1];
314}
315
316/* encode pitch wheel change */
317static void pitchbend_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
318{
319 ev->data.control.channel = dev->buf[0] & 0x0f;
320 ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1] - 8192;
321}
322
323/* encode midi control change */
324static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
325{
326 ev->data.control.channel = dev->buf[0] & 0x0f;
327 ev->data.control.param = dev->buf[1];
328 ev->data.control.value = dev->buf[2];
329}
330
331/* encode one parameter value*/
332static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
333{
334 ev->data.control.value = dev->buf[1];
335}
336
337/* encode song position */
338static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev)
339{
340 ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1];
341}
342
343/*
344 * decode from a sequencer event to midi bytes
345 * return the size of decoded midi events
346 */
347long snd_midi_event_decode(snd_midi_event_t *dev, unsigned char *buf, long count, snd_seq_event_t *ev)
348{
349 unsigned int cmd, type;
350
351 if (ev->type == SNDRV_SEQ_EVENT_NONE)
352 return -ENOENT;
353
354 for (type = 0; type < ARRAY_SIZE(status_event); type++) {
355 if (ev->type == status_event[type].event)
356 goto __found;
357 }
358 for (type = 0; type < ARRAY_SIZE(extra_event); type++) {
359 if (ev->type == extra_event[type].event)
360 return extra_event[type].decode(dev, buf, count, ev);
361 }
362 return -ENOENT;
363
364 __found:
365 if (type >= ST_SPECIAL)
366 cmd = 0xf0 + (type - ST_SPECIAL);
367 else
368 /* data.note.channel and data.control.channel is identical */
369 cmd = 0x80 | (type << 4) | (ev->data.note.channel & 0x0f);
370
371
372 if (cmd == MIDI_CMD_COMMON_SYSEX) {
373 snd_midi_event_reset_decode(dev);
374 return snd_seq_expand_var_event(ev, count, buf, 1, 0);
375 } else {
376 int qlen;
377 unsigned char xbuf[4];
378 unsigned long flags;
379
380 spin_lock_irqsave(&dev->lock, flags);
381 if ((cmd & 0xf0) == 0xf0 || dev->lastcmd != cmd || dev->nostat) {
382 dev->lastcmd = cmd;
383 spin_unlock_irqrestore(&dev->lock, flags);
384 xbuf[0] = cmd;
385 if (status_event[type].decode)
386 status_event[type].decode(ev, xbuf + 1);
387 qlen = status_event[type].qlen + 1;
388 } else {
389 spin_unlock_irqrestore(&dev->lock, flags);
390 if (status_event[type].decode)
391 status_event[type].decode(ev, xbuf + 0);
392 qlen = status_event[type].qlen;
393 }
394 if (count < qlen)
395 return -ENOMEM;
396 memcpy(buf, xbuf, qlen);
397 return qlen;
398 }
399}
400
401
402/* decode note event */
403static void note_decode(snd_seq_event_t *ev, unsigned char *buf)
404{
405 buf[0] = ev->data.note.note & 0x7f;
406 buf[1] = ev->data.note.velocity & 0x7f;
407}
408
409/* decode one parameter controls */
410static void one_param_decode(snd_seq_event_t *ev, unsigned char *buf)
411{
412 buf[0] = ev->data.control.value & 0x7f;
413}
414
415/* decode pitch wheel change */
416static void pitchbend_decode(snd_seq_event_t *ev, unsigned char *buf)
417{
418 int value = ev->data.control.value + 8192;
419 buf[0] = value & 0x7f;
420 buf[1] = (value >> 7) & 0x7f;
421}
422
423/* decode midi control change */
424static void two_param_decode(snd_seq_event_t *ev, unsigned char *buf)
425{
426 buf[0] = ev->data.control.param & 0x7f;
427 buf[1] = ev->data.control.value & 0x7f;
428}
429
430/* decode song position */
431static void songpos_decode(snd_seq_event_t *ev, unsigned char *buf)
432{
433 buf[0] = ev->data.control.value & 0x7f;
434 buf[1] = (ev->data.control.value >> 7) & 0x7f;
435}
436
437/* decode 14bit control */
438static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev)
439{
440 unsigned char cmd;
441 int idx = 0;
442
443 cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
444 if (ev->data.control.param < 0x20) {
445 if (count < 4)
446 return -ENOMEM;
447 if (dev->nostat && count < 6)
448 return -ENOMEM;
449 if (cmd != dev->lastcmd || dev->nostat) {
450 if (count < 5)
451 return -ENOMEM;
452 buf[idx++] = dev->lastcmd = cmd;
453 }
454 buf[idx++] = ev->data.control.param;
455 buf[idx++] = (ev->data.control.value >> 7) & 0x7f;
456 if (dev->nostat)
457 buf[idx++] = cmd;
458 buf[idx++] = ev->data.control.param + 0x20;
459 buf[idx++] = ev->data.control.value & 0x7f;
460 } else {
461 if (count < 2)
462 return -ENOMEM;
463 if (cmd != dev->lastcmd || dev->nostat) {
464 if (count < 3)
465 return -ENOMEM;
466 buf[idx++] = dev->lastcmd = cmd;
467 }
468 buf[idx++] = ev->data.control.param & 0x7f;
469 buf[idx++] = ev->data.control.value & 0x7f;
470 }
471 return idx;
472}
473
474/* decode reg/nonreg param */
475static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev)
476{
477 unsigned char cmd;
478 char *cbytes;
479 static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB,
480 MIDI_CTL_NONREG_PARM_NUM_LSB,
481 MIDI_CTL_MSB_DATA_ENTRY,
482 MIDI_CTL_LSB_DATA_ENTRY };
483 static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB,
484 MIDI_CTL_REGIST_PARM_NUM_LSB,
485 MIDI_CTL_MSB_DATA_ENTRY,
486 MIDI_CTL_LSB_DATA_ENTRY };
487 unsigned char bytes[4];
488 int idx = 0, i;
489
490 if (count < 8)
491 return -ENOMEM;
492 if (dev->nostat && count < 12)
493 return -ENOMEM;
494 cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f);
495 bytes[0] = ev->data.control.param & 0x007f;
496 bytes[1] = (ev->data.control.param & 0x3f80) >> 7;
497 bytes[2] = ev->data.control.value & 0x007f;
498 bytes[3] = (ev->data.control.value & 0x3f80) >> 7;
499 if (cmd != dev->lastcmd && !dev->nostat) {
500 if (count < 9)
501 return -ENOMEM;
502 buf[idx++] = dev->lastcmd = cmd;
503 }
504 cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn;
505 for (i = 0; i < 4; i++) {
506 if (dev->nostat)
507 buf[idx++] = dev->lastcmd = cmd;
508 buf[idx++] = cbytes[i];
509 buf[idx++] = bytes[i];
510 }
511 return idx;
512}
513
514/*
515 * exports
516 */
517
518EXPORT_SYMBOL(snd_midi_event_new);
519EXPORT_SYMBOL(snd_midi_event_free);
520EXPORT_SYMBOL(snd_midi_event_resize_buffer);
521EXPORT_SYMBOL(snd_midi_event_init);
522EXPORT_SYMBOL(snd_midi_event_reset_encode);
523EXPORT_SYMBOL(snd_midi_event_reset_decode);
524EXPORT_SYMBOL(snd_midi_event_no_status);
525EXPORT_SYMBOL(snd_midi_event_encode);
526EXPORT_SYMBOL(snd_midi_event_encode_byte);
527EXPORT_SYMBOL(snd_midi_event_decode);
528
529static int __init alsa_seq_midi_event_init(void)
530{
531 return 0;
532}
533
534static void __exit alsa_seq_midi_event_exit(void)
535{
536}
537
538module_init(alsa_seq_midi_event_init)
539module_exit(alsa_seq_midi_event_exit)
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c
new file mode 100644
index 000000000000..b976951fc100
--- /dev/null
+++ b/sound/core/seq/seq_ports.c
@@ -0,0 +1,674 @@
1/*
2 * ALSA sequencer Ports
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
4 * Jaroslav Kysela <perex@suse.cz>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <sound/core.h>
25#include <linux/slab.h>
26#include "seq_system.h"
27#include "seq_ports.h"
28#include "seq_clientmgr.h"
29
30/*
31
32 registration of client ports
33
34 */
35
36
37/*
38
39NOTE: the current implementation of the port structure as a linked list is
40not optimal for clients that have many ports. For sending messages to all
41subscribers of a port we first need to find the address of the port
42structure, which means we have to traverse the list. A direct access table
43(array) would be better, but big preallocated arrays waste memory.
44
45Possible actions:
46
471) leave it this way, a client does normaly does not have more than a few
48ports
49
502) replace the linked list of ports by a array of pointers which is
51dynamicly kmalloced. When a port is added or deleted we can simply allocate
52a new array, copy the corresponding pointers, and delete the old one. We
53then only need a pointer to this array, and an integer that tells us how
54much elements are in array.
55
56*/
57
58/* return pointer to port structure - port is locked if found */
59client_port_t *snd_seq_port_use_ptr(client_t *client, int num)
60{
61 struct list_head *p;
62 client_port_t *port;
63
64 if (client == NULL)
65 return NULL;
66 read_lock(&client->ports_lock);
67 list_for_each(p, &client->ports_list_head) {
68 port = list_entry(p, client_port_t, list);
69 if (port->addr.port == num) {
70 if (port->closing)
71 break; /* deleting now */
72 snd_use_lock_use(&port->use_lock);
73 read_unlock(&client->ports_lock);
74 return port;
75 }
76 }
77 read_unlock(&client->ports_lock);
78 return NULL; /* not found */
79}
80
81
82/* search for the next port - port is locked if found */
83client_port_t *snd_seq_port_query_nearest(client_t *client, snd_seq_port_info_t *pinfo)
84{
85 int num;
86 struct list_head *p;
87 client_port_t *port, *found;
88
89 num = pinfo->addr.port;
90 found = NULL;
91 read_lock(&client->ports_lock);
92 list_for_each(p, &client->ports_list_head) {
93 port = list_entry(p, client_port_t, list);
94 if (port->addr.port < num)
95 continue;
96 if (port->addr.port == num) {
97 found = port;
98 break;
99 }
100 if (found == NULL || port->addr.port < found->addr.port)
101 found = port;
102 }
103 if (found) {
104 if (found->closing)
105 found = NULL;
106 else
107 snd_use_lock_use(&found->use_lock);
108 }
109 read_unlock(&client->ports_lock);
110 return found;
111}
112
113
114/* initialize port_subs_info_t */
115static void port_subs_info_init(port_subs_info_t *grp)
116{
117 INIT_LIST_HEAD(&grp->list_head);
118 grp->count = 0;
119 grp->exclusive = 0;
120 rwlock_init(&grp->list_lock);
121 init_rwsem(&grp->list_mutex);
122 grp->open = NULL;
123 grp->close = NULL;
124}
125
126
127/* create a port, port number is returned (-1 on failure) */
128client_port_t *snd_seq_create_port(client_t *client, int port)
129{
130 unsigned long flags;
131 client_port_t *new_port;
132 struct list_head *l;
133 int num = -1;
134
135 /* sanity check */
136 snd_assert(client, return NULL);
137
138 if (client->num_ports >= SNDRV_SEQ_MAX_PORTS - 1) {
139 snd_printk(KERN_WARNING "too many ports for client %d\n", client->number);
140 return NULL;
141 }
142
143 /* create a new port */
144 new_port = kcalloc(1, sizeof(*new_port), GFP_KERNEL);
145 if (! new_port) {
146 snd_printd("malloc failed for registering client port\n");
147 return NULL; /* failure, out of memory */
148 }
149 /* init port data */
150 new_port->addr.client = client->number;
151 new_port->addr.port = -1;
152 new_port->owner = THIS_MODULE;
153 sprintf(new_port->name, "port-%d", num);
154 snd_use_lock_init(&new_port->use_lock);
155 port_subs_info_init(&new_port->c_src);
156 port_subs_info_init(&new_port->c_dest);
157
158 num = port >= 0 ? port : 0;
159 down(&client->ports_mutex);
160 write_lock_irqsave(&client->ports_lock, flags);
161 list_for_each(l, &client->ports_list_head) {
162 client_port_t *p = list_entry(l, client_port_t, list);
163 if (p->addr.port > num)
164 break;
165 if (port < 0) /* auto-probe mode */
166 num = p->addr.port + 1;
167 }
168 /* insert the new port */
169 list_add_tail(&new_port->list, l);
170 client->num_ports++;
171 new_port->addr.port = num; /* store the port number in the port */
172 write_unlock_irqrestore(&client->ports_lock, flags);
173 up(&client->ports_mutex);
174 sprintf(new_port->name, "port-%d", num);
175
176 return new_port;
177}
178
179/* */
180enum group_type_t {
181 SRC_LIST, DEST_LIST
182};
183
184static int subscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp, snd_seq_port_subscribe_t *info, int send_ack);
185static int unsubscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp, snd_seq_port_subscribe_t *info, int send_ack);
186
187
188static client_port_t *get_client_port(snd_seq_addr_t *addr, client_t **cp)
189{
190 client_port_t *p;
191 *cp = snd_seq_client_use_ptr(addr->client);
192 if (*cp) {
193 p = snd_seq_port_use_ptr(*cp, addr->port);
194 if (! p) {
195 snd_seq_client_unlock(*cp);
196 *cp = NULL;
197 }
198 return p;
199 }
200 return NULL;
201}
202
203/*
204 * remove all subscribers on the list
205 * this is called from port_delete, for each src and dest list.
206 */
207static void clear_subscriber_list(client_t *client, client_port_t *port,
208 port_subs_info_t *grp, int grptype)
209{
210 struct list_head *p, *n;
211
212 down_write(&grp->list_mutex);
213 list_for_each_safe(p, n, &grp->list_head) {
214 subscribers_t *subs;
215 client_t *c;
216 client_port_t *aport;
217
218 if (grptype == SRC_LIST) {
219 subs = list_entry(p, subscribers_t, src_list);
220 aport = get_client_port(&subs->info.dest, &c);
221 } else {
222 subs = list_entry(p, subscribers_t, dest_list);
223 aport = get_client_port(&subs->info.sender, &c);
224 }
225 list_del(p);
226 unsubscribe_port(client, port, grp, &subs->info, 0);
227 if (!aport) {
228 /* looks like the connected port is being deleted.
229 * we decrease the counter, and when both ports are deleted
230 * remove the subscriber info
231 */
232 if (atomic_dec_and_test(&subs->ref_count))
233 kfree(subs);
234 } else {
235 /* ok we got the connected port */
236 port_subs_info_t *agrp;
237 agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src;
238 down_write(&agrp->list_mutex);
239 if (grptype == SRC_LIST)
240 list_del(&subs->dest_list);
241 else
242 list_del(&subs->src_list);
243 unsubscribe_port(c, aport, agrp, &subs->info, 1);
244 kfree(subs);
245 up_write(&agrp->list_mutex);
246 snd_seq_port_unlock(aport);
247 snd_seq_client_unlock(c);
248 }
249 }
250 up_write(&grp->list_mutex);
251}
252
253/* delete port data */
254static int port_delete(client_t *client, client_port_t *port)
255{
256 /* set closing flag and wait for all port access are gone */
257 port->closing = 1;
258 snd_use_lock_sync(&port->use_lock);
259
260 /* clear subscribers info */
261 clear_subscriber_list(client, port, &port->c_src, SRC_LIST);
262 clear_subscriber_list(client, port, &port->c_dest, DEST_LIST);
263
264 if (port->private_free)
265 port->private_free(port->private_data);
266
267 snd_assert(port->c_src.count == 0,);
268 snd_assert(port->c_dest.count == 0,);
269
270 kfree(port);
271 return 0;
272}
273
274
275/* delete a port with the given port id */
276int snd_seq_delete_port(client_t *client, int port)
277{
278 unsigned long flags;
279 struct list_head *l;
280 client_port_t *found = NULL;
281
282 down(&client->ports_mutex);
283 write_lock_irqsave(&client->ports_lock, flags);
284 list_for_each(l, &client->ports_list_head) {
285 client_port_t *p = list_entry(l, client_port_t, list);
286 if (p->addr.port == port) {
287 /* ok found. delete from the list at first */
288 list_del(l);
289 client->num_ports--;
290 found = p;
291 break;
292 }
293 }
294 write_unlock_irqrestore(&client->ports_lock, flags);
295 up(&client->ports_mutex);
296 if (found)
297 return port_delete(client, found);
298 else
299 return -ENOENT;
300}
301
302/* delete the all ports belonging to the given client */
303int snd_seq_delete_all_ports(client_t *client)
304{
305 unsigned long flags;
306 struct list_head deleted_list, *p, *n;
307
308 /* move the port list to deleted_list, and
309 * clear the port list in the client data.
310 */
311 down(&client->ports_mutex);
312 write_lock_irqsave(&client->ports_lock, flags);
313 if (! list_empty(&client->ports_list_head)) {
314 __list_add(&deleted_list,
315 client->ports_list_head.prev,
316 client->ports_list_head.next);
317 INIT_LIST_HEAD(&client->ports_list_head);
318 } else {
319 INIT_LIST_HEAD(&deleted_list);
320 }
321 client->num_ports = 0;
322 write_unlock_irqrestore(&client->ports_lock, flags);
323
324 /* remove each port in deleted_list */
325 list_for_each_safe(p, n, &deleted_list) {
326 client_port_t *port = list_entry(p, client_port_t, list);
327 list_del(p);
328 snd_seq_system_client_ev_port_exit(port->addr.client, port->addr.port);
329 port_delete(client, port);
330 }
331 up(&client->ports_mutex);
332 return 0;
333}
334
335/* set port info fields */
336int snd_seq_set_port_info(client_port_t * port, snd_seq_port_info_t * info)
337{
338 snd_assert(port && info, return -EINVAL);
339
340 /* set port name */
341 if (info->name[0])
342 strlcpy(port->name, info->name, sizeof(port->name));
343
344 /* set capabilities */
345 port->capability = info->capability;
346
347 /* get port type */
348 port->type = info->type;
349
350 /* information about supported channels/voices */
351 port->midi_channels = info->midi_channels;
352 port->midi_voices = info->midi_voices;
353 port->synth_voices = info->synth_voices;
354
355 /* timestamping */
356 port->timestamping = (info->flags & SNDRV_SEQ_PORT_FLG_TIMESTAMP) ? 1 : 0;
357 port->time_real = (info->flags & SNDRV_SEQ_PORT_FLG_TIME_REAL) ? 1 : 0;
358 port->time_queue = info->time_queue;
359
360 return 0;
361}
362
363/* get port info fields */
364int snd_seq_get_port_info(client_port_t * port, snd_seq_port_info_t * info)
365{
366 snd_assert(port && info, return -EINVAL);
367
368 /* get port name */
369 strlcpy(info->name, port->name, sizeof(info->name));
370
371 /* get capabilities */
372 info->capability = port->capability;
373
374 /* get port type */
375 info->type = port->type;
376
377 /* information about supported channels/voices */
378 info->midi_channels = port->midi_channels;
379 info->midi_voices = port->midi_voices;
380 info->synth_voices = port->synth_voices;
381
382 /* get subscriber counts */
383 info->read_use = port->c_src.count;
384 info->write_use = port->c_dest.count;
385
386 /* timestamping */
387 info->flags = 0;
388 if (port->timestamping) {
389 info->flags |= SNDRV_SEQ_PORT_FLG_TIMESTAMP;
390 if (port->time_real)
391 info->flags |= SNDRV_SEQ_PORT_FLG_TIME_REAL;
392 info->time_queue = port->time_queue;
393 }
394
395 return 0;
396}
397
398
399
400/*
401 * call callback functions (if any):
402 * the callbacks are invoked only when the first (for connection) or
403 * the last subscription (for disconnection) is done. Second or later
404 * subscription results in increment of counter, but no callback is
405 * invoked.
406 * This feature is useful if these callbacks are associated with
407 * initialization or termination of devices (see seq_midi.c).
408 *
409 * If callback_all option is set, the callback function is invoked
410 * at each connnection/disconnection.
411 */
412
413static int subscribe_port(client_t *client, client_port_t *port, port_subs_info_t *grp,
414 snd_seq_port_subscribe_t *info, int send_ack)
415{
416 int err = 0;
417
418 if (!try_module_get(port->owner))
419 return -EFAULT;
420 grp->count++;
421 if (grp->open && (port->callback_all || grp->count == 1)) {
422 err = grp->open(port->private_data, info);
423 if (err < 0) {
424 module_put(port->owner);
425 grp->count--;
426 }
427 }
428 if (err >= 0 && send_ack && client->type == USER_CLIENT)
429 snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
430 info, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
431
432 return err;
433}
434
435static int unsubscribe_port(client_t *client, client_port_t *port,
436 port_subs_info_t *grp,
437 snd_seq_port_subscribe_t *info, int send_ack)
438{
439 int err = 0;
440
441 if (! grp->count)
442 return -EINVAL;
443 grp->count--;
444 if (grp->close && (port->callback_all || grp->count == 0))
445 err = grp->close(port->private_data, info);
446 if (send_ack && client->type == USER_CLIENT)
447 snd_seq_client_notify_subscription(port->addr.client, port->addr.port,
448 info, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
449 module_put(port->owner);
450 return err;
451}
452
453
454
455/* check if both addresses are identical */
456static inline int addr_match(snd_seq_addr_t *r, snd_seq_addr_t *s)
457{
458 return (r->client == s->client) && (r->port == s->port);
459}
460
461/* check the two subscribe info match */
462/* if flags is zero, checks only sender and destination addresses */
463static int match_subs_info(snd_seq_port_subscribe_t *r,
464 snd_seq_port_subscribe_t *s)
465{
466 if (addr_match(&r->sender, &s->sender) &&
467 addr_match(&r->dest, &s->dest)) {
468 if (r->flags && r->flags == s->flags)
469 return r->queue == s->queue;
470 else if (! r->flags)
471 return 1;
472 }
473 return 0;
474}
475
476
477/* connect two ports */
478int snd_seq_port_connect(client_t *connector,
479 client_t *src_client, client_port_t *src_port,
480 client_t *dest_client, client_port_t *dest_port,
481 snd_seq_port_subscribe_t *info)
482{
483 port_subs_info_t *src = &src_port->c_src;
484 port_subs_info_t *dest = &dest_port->c_dest;
485 subscribers_t *subs;
486 struct list_head *p;
487 int err, src_called = 0;
488 unsigned long flags;
489 int exclusive;
490
491 subs = kcalloc(1, sizeof(*subs), GFP_KERNEL);
492 if (! subs)
493 return -ENOMEM;
494
495 subs->info = *info;
496 atomic_set(&subs->ref_count, 2);
497
498 down_write(&src->list_mutex);
499 down_write(&dest->list_mutex);
500
501 exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0;
502 err = -EBUSY;
503 if (exclusive) {
504 if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head))
505 goto __error;
506 } else {
507 if (src->exclusive || dest->exclusive)
508 goto __error;
509 /* check whether already exists */
510 list_for_each(p, &src->list_head) {
511 subscribers_t *s = list_entry(p, subscribers_t, src_list);
512 if (match_subs_info(info, &s->info))
513 goto __error;
514 }
515 list_for_each(p, &dest->list_head) {
516 subscribers_t *s = list_entry(p, subscribers_t, dest_list);
517 if (match_subs_info(info, &s->info))
518 goto __error;
519 }
520 }
521
522 if ((err = subscribe_port(src_client, src_port, src, info,
523 connector->number != src_client->number)) < 0)
524 goto __error;
525 src_called = 1;
526
527 if ((err = subscribe_port(dest_client, dest_port, dest, info,
528 connector->number != dest_client->number)) < 0)
529 goto __error;
530
531 /* add to list */
532 write_lock_irqsave(&src->list_lock, flags);
533 // write_lock(&dest->list_lock); // no other lock yet
534 list_add_tail(&subs->src_list, &src->list_head);
535 list_add_tail(&subs->dest_list, &dest->list_head);
536 // write_unlock(&dest->list_lock); // no other lock yet
537 write_unlock_irqrestore(&src->list_lock, flags);
538
539 src->exclusive = dest->exclusive = exclusive;
540
541 up_write(&dest->list_mutex);
542 up_write(&src->list_mutex);
543 return 0;
544
545 __error:
546 if (src_called)
547 unsubscribe_port(src_client, src_port, src, info,
548 connector->number != src_client->number);
549 kfree(subs);
550 up_write(&dest->list_mutex);
551 up_write(&src->list_mutex);
552 return err;
553}
554
555
556/* remove the connection */
557int snd_seq_port_disconnect(client_t *connector,
558 client_t *src_client, client_port_t *src_port,
559 client_t *dest_client, client_port_t *dest_port,
560 snd_seq_port_subscribe_t *info)
561{
562 port_subs_info_t *src = &src_port->c_src;
563 port_subs_info_t *dest = &dest_port->c_dest;
564 subscribers_t *subs;
565 struct list_head *p;
566 int err = -ENOENT;
567 unsigned long flags;
568
569 down_write(&src->list_mutex);
570 down_write(&dest->list_mutex);
571
572 /* look for the connection */
573 list_for_each(p, &src->list_head) {
574 subs = list_entry(p, subscribers_t, src_list);
575 if (match_subs_info(info, &subs->info)) {
576 write_lock_irqsave(&src->list_lock, flags);
577 // write_lock(&dest->list_lock); // no lock yet
578 list_del(&subs->src_list);
579 list_del(&subs->dest_list);
580 // write_unlock(&dest->list_lock);
581 write_unlock_irqrestore(&src->list_lock, flags);
582 src->exclusive = dest->exclusive = 0;
583 unsubscribe_port(src_client, src_port, src, info,
584 connector->number != src_client->number);
585 unsubscribe_port(dest_client, dest_port, dest, info,
586 connector->number != dest_client->number);
587 kfree(subs);
588 err = 0;
589 break;
590 }
591 }
592
593 up_write(&dest->list_mutex);
594 up_write(&src->list_mutex);
595 return err;
596}
597
598
599/* get matched subscriber */
600subscribers_t *snd_seq_port_get_subscription(port_subs_info_t *src_grp,
601 snd_seq_addr_t *dest_addr)
602{
603 struct list_head *p;
604 subscribers_t *s, *found = NULL;
605
606 down_read(&src_grp->list_mutex);
607 list_for_each(p, &src_grp->list_head) {
608 s = list_entry(p, subscribers_t, src_list);
609 if (addr_match(dest_addr, &s->info.dest)) {
610 found = s;
611 break;
612 }
613 }
614 up_read(&src_grp->list_mutex);
615 return found;
616}
617
618/*
619 * Attach a device driver that wants to receive events from the
620 * sequencer. Returns the new port number on success.
621 * A driver that wants to receive the events converted to midi, will
622 * use snd_seq_midisynth_register_port().
623 */
624/* exported */
625int snd_seq_event_port_attach(int client,
626 snd_seq_port_callback_t *pcbp,
627 int cap, int type, int midi_channels,
628 int midi_voices, char *portname)
629{
630 snd_seq_port_info_t portinfo;
631 int ret;
632
633 /* Set up the port */
634 memset(&portinfo, 0, sizeof(portinfo));
635 portinfo.addr.client = client;
636 strlcpy(portinfo.name, portname ? portname : "Unamed port",
637 sizeof(portinfo.name));
638
639 portinfo.capability = cap;
640 portinfo.type = type;
641 portinfo.kernel = pcbp;
642 portinfo.midi_channels = midi_channels;
643 portinfo.midi_voices = midi_voices;
644
645 /* Create it */
646 ret = snd_seq_kernel_client_ctl(client,
647 SNDRV_SEQ_IOCTL_CREATE_PORT,
648 &portinfo);
649
650 if (ret >= 0)
651 ret = portinfo.addr.port;
652
653 return ret;
654}
655
656
657/*
658 * Detach the driver from a port.
659 */
660/* exported */
661int snd_seq_event_port_detach(int client, int port)
662{
663 snd_seq_port_info_t portinfo;
664 int err;
665
666 memset(&portinfo, 0, sizeof(portinfo));
667 portinfo.addr.client = client;
668 portinfo.addr.port = port;
669 err = snd_seq_kernel_client_ctl(client,
670 SNDRV_SEQ_IOCTL_DELETE_PORT,
671 &portinfo);
672
673 return err;
674}
diff --git a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h
new file mode 100644
index 000000000000..89fd4416f6fa
--- /dev/null
+++ b/sound/core/seq/seq_ports.h
@@ -0,0 +1,128 @@
1/*
2 * ALSA sequencer Ports
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_PORTS_H
22#define __SND_SEQ_PORTS_H
23
24#include <sound/seq_kernel.h>
25#include "seq_lock.h"
26
27/* list of 'exported' ports */
28
29/* Client ports that are not exported are still accessible, but are
30 anonymous ports.
31
32 If a port supports SUBSCRIPTION, that port can send events to all
33 subscribersto a special address, with address
34 (queue==SNDRV_SEQ_ADDRESS_SUBSCRIBERS). The message is then send to all
35 recipients that are registered in the subscription list. A typical
36 application for these SUBSCRIPTION events is handling of incoming MIDI
37 data. The port doesn't 'know' what other clients are interested in this
38 message. If for instance a MIDI recording application would like to receive
39 the events from that port, it will first have to subscribe with that port.
40
41*/
42
43typedef struct subscribers_t {
44 snd_seq_port_subscribe_t info; /* additional info */
45 struct list_head src_list; /* link of sources */
46 struct list_head dest_list; /* link of destinations */
47 atomic_t ref_count;
48} subscribers_t;
49
50typedef struct port_subs_info_t {
51 struct list_head list_head; /* list of subscribed ports */
52 unsigned int count; /* count of subscribers */
53 unsigned int exclusive: 1; /* exclusive mode */
54 struct rw_semaphore list_mutex;
55 rwlock_t list_lock;
56 snd_seq_kernel_port_open_t *open;
57 snd_seq_kernel_port_close_t *close;
58} port_subs_info_t;
59
60typedef struct client_port_t {
61
62 snd_seq_addr_t addr; /* client/port number */
63 struct module *owner; /* owner of this port */
64 char name[64]; /* port name */
65 struct list_head list; /* port list */
66 snd_use_lock_t use_lock;
67
68 /* subscribers */
69 port_subs_info_t c_src; /* read (sender) list */
70 port_subs_info_t c_dest; /* write (dest) list */
71
72 snd_seq_kernel_port_input_t *event_input;
73 snd_seq_kernel_port_private_free_t *private_free;
74 void *private_data;
75 unsigned int callback_all : 1;
76 unsigned int closing : 1;
77 unsigned int timestamping: 1;
78 unsigned int time_real: 1;
79 int time_queue;
80
81 /* capability, inport, output, sync */
82 unsigned int capability; /* port capability bits */
83 unsigned int type; /* port type bits */
84
85 /* supported channels */
86 int midi_channels;
87 int midi_voices;
88 int synth_voices;
89
90} client_port_t;
91
92/* return pointer to port structure and lock port */
93client_port_t *snd_seq_port_use_ptr(client_t *client, int num);
94
95/* search for next port - port is locked if found */
96client_port_t *snd_seq_port_query_nearest(client_t *client, snd_seq_port_info_t *pinfo);
97
98/* unlock the port */
99#define snd_seq_port_unlock(port) snd_use_lock_free(&(port)->use_lock)
100
101/* create a port, port number is returned (-1 on failure) */
102client_port_t *snd_seq_create_port(client_t *client, int port_index);
103
104/* delete a port */
105int snd_seq_delete_port(client_t *client, int port);
106
107/* delete all ports */
108int snd_seq_delete_all_ports(client_t *client);
109
110/* set port info fields */
111int snd_seq_set_port_info(client_port_t *port, snd_seq_port_info_t *info);
112
113/* get port info fields */
114int snd_seq_get_port_info(client_port_t *port, snd_seq_port_info_t *info);
115
116/* add subscriber to subscription list */
117int snd_seq_port_connect(client_t *caller, client_t *s, client_port_t *sp, client_t *d, client_port_t *dp, snd_seq_port_subscribe_t *info);
118
119/* remove subscriber from subscription list */
120int snd_seq_port_disconnect(client_t *caller, client_t *s, client_port_t *sp, client_t *d, client_port_t *dp, snd_seq_port_subscribe_t *info);
121
122/* subscribe port */
123int snd_seq_port_subscribe(client_port_t *port, snd_seq_port_subscribe_t *info);
124
125/* get matched subscriber */
126subscribers_t *snd_seq_port_get_subscription(port_subs_info_t *src_grp, snd_seq_addr_t *dest_addr);
127
128#endif
diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
new file mode 100644
index 000000000000..a519732ed833
--- /dev/null
+++ b/sound/core/seq/seq_prioq.c
@@ -0,0 +1,449 @@
1/*
2 * ALSA sequencer Priority Queue
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
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/time.h>
24#include <linux/slab.h>
25#include <sound/core.h>
26#include "seq_timer.h"
27#include "seq_prioq.h"
28
29
30/* Implementation is a simple linked list for now...
31
32 This priority queue orders the events on timestamp. For events with an
33 equeal timestamp the queue behaves as a FIFO.
34
35 *
36 * +-------+
37 * Head --> | first |
38 * +-------+
39 * |next
40 * +-----v-+
41 * | |
42 * +-------+
43 * |
44 * +-----v-+
45 * | |
46 * +-------+
47 * |
48 * +-----v-+
49 * Tail --> | last |
50 * +-------+
51 *
52
53 */
54
55
56
57/* create new prioq (constructor) */
58prioq_t *snd_seq_prioq_new(void)
59{
60 prioq_t *f;
61
62 f = kcalloc(1, sizeof(*f), GFP_KERNEL);
63 if (f == NULL) {
64 snd_printd("oops: malloc failed for snd_seq_prioq_new()\n");
65 return NULL;
66 }
67
68 spin_lock_init(&f->lock);
69 f->head = NULL;
70 f->tail = NULL;
71 f->cells = 0;
72
73 return f;
74}
75
76/* delete prioq (destructor) */
77void snd_seq_prioq_delete(prioq_t **fifo)
78{
79 prioq_t *f = *fifo;
80 *fifo = NULL;
81
82 if (f == NULL) {
83 snd_printd("oops: snd_seq_prioq_delete() called with NULL prioq\n");
84 return;
85 }
86
87 /* release resources...*/
88 /*....................*/
89
90 if (f->cells > 0) {
91 /* drain prioQ */
92 while (f->cells > 0)
93 snd_seq_cell_free(snd_seq_prioq_cell_out(f));
94 }
95
96 kfree(f);
97}
98
99
100
101
102/* compare timestamp between events */
103/* return 1 if a >= b; 0 */
104static inline int compare_timestamp(snd_seq_event_t * a, snd_seq_event_t * b)
105{
106 if ((a->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) {
107 /* compare ticks */
108 return (snd_seq_compare_tick_time(&a->time.tick, &b->time.tick));
109 } else {
110 /* compare real time */
111 return (snd_seq_compare_real_time(&a->time.time, &b->time.time));
112 }
113}
114
115/* compare timestamp between events */
116/* return negative if a < b;
117 * zero if a = b;
118 * positive if a > b;
119 */
120static inline int compare_timestamp_rel(snd_seq_event_t *a, snd_seq_event_t *b)
121{
122 if ((a->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) {
123 /* compare ticks */
124 if (a->time.tick > b->time.tick)
125 return 1;
126 else if (a->time.tick == b->time.tick)
127 return 0;
128 else
129 return -1;
130 } else {
131 /* compare real time */
132 if (a->time.time.tv_sec > b->time.time.tv_sec)
133 return 1;
134 else if (a->time.time.tv_sec == b->time.time.tv_sec) {
135 if (a->time.time.tv_nsec > b->time.time.tv_nsec)
136 return 1;
137 else if (a->time.time.tv_nsec == b->time.time.tv_nsec)
138 return 0;
139 else
140 return -1;
141 } else
142 return -1;
143 }
144}
145
146/* enqueue cell to prioq */
147int snd_seq_prioq_cell_in(prioq_t * f, snd_seq_event_cell_t * cell)
148{
149 snd_seq_event_cell_t *cur, *prev;
150 unsigned long flags;
151 int count;
152 int prior;
153
154 snd_assert(f, return -EINVAL);
155 snd_assert(cell, return -EINVAL);
156
157 /* check flags */
158 prior = (cell->event.flags & SNDRV_SEQ_PRIORITY_MASK);
159
160 spin_lock_irqsave(&f->lock, flags);
161
162 /* check if this element needs to inserted at the end (ie. ordered
163 data is inserted) This will be very likeley if a sequencer
164 application or midi file player is feeding us (sequential) data */
165 if (f->tail && !prior) {
166 if (compare_timestamp(&cell->event, &f->tail->event)) {
167 /* add new cell to tail of the fifo */
168 f->tail->next = cell;
169 f->tail = cell;
170 cell->next = NULL;
171 f->cells++;
172 spin_unlock_irqrestore(&f->lock, flags);
173 return 0;
174 }
175 }
176 /* traverse list of elements to find the place where the new cell is
177 to be inserted... Note that this is a order n process ! */
178
179 prev = NULL; /* previous cell */
180 cur = f->head; /* cursor */
181
182 count = 10000; /* FIXME: enough big, isn't it? */
183 while (cur != NULL) {
184 /* compare timestamps */
185 int rel = compare_timestamp_rel(&cell->event, &cur->event);
186 if (rel < 0)
187 /* new cell has earlier schedule time, */
188 break;
189 else if (rel == 0 && prior)
190 /* equal schedule time and prior to others */
191 break;
192 /* new cell has equal or larger schedule time, */
193 /* move cursor to next cell */
194 prev = cur;
195 cur = cur->next;
196 if (! --count) {
197 spin_unlock_irqrestore(&f->lock, flags);
198 snd_printk(KERN_ERR "cannot find a pointer.. infinite loop?\n");
199 return -EINVAL;
200 }
201 }
202
203 /* insert it before cursor */
204 if (prev != NULL)
205 prev->next = cell;
206 cell->next = cur;
207
208 if (f->head == cur) /* this is the first cell, set head to it */
209 f->head = cell;
210 if (cur == NULL) /* reached end of the list */
211 f->tail = cell;
212 f->cells++;
213 spin_unlock_irqrestore(&f->lock, flags);
214 return 0;
215}
216
217/* dequeue cell from prioq */
218snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t * f)
219{
220 snd_seq_event_cell_t *cell;
221 unsigned long flags;
222
223 if (f == NULL) {
224 snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
225 return NULL;
226 }
227 spin_lock_irqsave(&f->lock, flags);
228
229 cell = f->head;
230 if (cell) {
231 f->head = cell->next;
232
233 /* reset tail if this was the last element */
234 if (f->tail == cell)
235 f->tail = NULL;
236
237 cell->next = NULL;
238 f->cells--;
239 }
240
241 spin_unlock_irqrestore(&f->lock, flags);
242 return cell;
243}
244
245/* return number of events available in prioq */
246int snd_seq_prioq_avail(prioq_t * f)
247{
248 if (f == NULL) {
249 snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
250 return 0;
251 }
252 return f->cells;
253}
254
255
256/* peek at cell at the head of the prioq */
257snd_seq_event_cell_t *snd_seq_prioq_cell_peek(prioq_t * f)
258{
259 if (f == NULL) {
260 snd_printd("oops: snd_seq_prioq_cell_in() called with NULL prioq\n");
261 return NULL;
262 }
263 return f->head;
264}
265
266
267static inline int prioq_match(snd_seq_event_cell_t *cell, int client, int timestamp)
268{
269 if (cell->event.source.client == client ||
270 cell->event.dest.client == client)
271 return 1;
272 if (!timestamp)
273 return 0;
274 switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
275 case SNDRV_SEQ_TIME_STAMP_TICK:
276 if (cell->event.time.tick)
277 return 1;
278 break;
279 case SNDRV_SEQ_TIME_STAMP_REAL:
280 if (cell->event.time.time.tv_sec ||
281 cell->event.time.time.tv_nsec)
282 return 1;
283 break;
284 }
285 return 0;
286}
287
288/* remove cells for left client */
289void snd_seq_prioq_leave(prioq_t * f, int client, int timestamp)
290{
291 register snd_seq_event_cell_t *cell, *next;
292 unsigned long flags;
293 snd_seq_event_cell_t *prev = NULL;
294 snd_seq_event_cell_t *freefirst = NULL, *freeprev = NULL, *freenext;
295
296 /* collect all removed cells */
297 spin_lock_irqsave(&f->lock, flags);
298 cell = f->head;
299 while (cell) {
300 next = cell->next;
301 if (prioq_match(cell, client, timestamp)) {
302 /* remove cell from prioq */
303 if (cell == f->head) {
304 f->head = cell->next;
305 } else {
306 prev->next = cell->next;
307 }
308 if (cell == f->tail)
309 f->tail = cell->next;
310 f->cells--;
311 /* add cell to free list */
312 cell->next = NULL;
313 if (freefirst == NULL) {
314 freefirst = cell;
315 } else {
316 freeprev->next = cell;
317 }
318 freeprev = cell;
319 } else {
320#if 0
321 printk("type = %i, source = %i, dest = %i, client = %i\n",
322 cell->event.type,
323 cell->event.source.client,
324 cell->event.dest.client,
325 client);
326#endif
327 prev = cell;
328 }
329 cell = next;
330 }
331 spin_unlock_irqrestore(&f->lock, flags);
332
333 /* remove selected cells */
334 while (freefirst) {
335 freenext = freefirst->next;
336 snd_seq_cell_free(freefirst);
337 freefirst = freenext;
338 }
339}
340
341static int prioq_remove_match(snd_seq_remove_events_t *info,
342 snd_seq_event_t *ev)
343{
344 int res;
345
346 if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
347 if (ev->dest.client != info->dest.client ||
348 ev->dest.port != info->dest.port)
349 return 0;
350 }
351 if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
352 if (! snd_seq_ev_is_channel_type(ev))
353 return 0;
354 /* data.note.channel and data.control.channel are identical */
355 if (ev->data.note.channel != info->channel)
356 return 0;
357 }
358 if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
359 if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
360 res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick);
361 else
362 res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
363 if (!res)
364 return 0;
365 }
366 if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
367 if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
368 res = snd_seq_compare_tick_time(&ev->time.tick, &info->time.tick);
369 else
370 res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
371 if (res)
372 return 0;
373 }
374 if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
375 if (ev->type != info->type)
376 return 0;
377 }
378 if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
379 /* Do not remove off events */
380 switch (ev->type) {
381 case SNDRV_SEQ_EVENT_NOTEOFF:
382 /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
383 return 0;
384 default:
385 break;
386 }
387 }
388 if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
389 if (info->tag != ev->tag)
390 return 0;
391 }
392
393 return 1;
394}
395
396/* remove cells matching remove criteria */
397void snd_seq_prioq_remove_events(prioq_t * f, int client,
398 snd_seq_remove_events_t *info)
399{
400 register snd_seq_event_cell_t *cell, *next;
401 unsigned long flags;
402 snd_seq_event_cell_t *prev = NULL;
403 snd_seq_event_cell_t *freefirst = NULL, *freeprev = NULL, *freenext;
404
405 /* collect all removed cells */
406 spin_lock_irqsave(&f->lock, flags);
407 cell = f->head;
408
409 while (cell) {
410 next = cell->next;
411 if (cell->event.source.client == client &&
412 prioq_remove_match(info, &cell->event)) {
413
414 /* remove cell from prioq */
415 if (cell == f->head) {
416 f->head = cell->next;
417 } else {
418 prev->next = cell->next;
419 }
420
421 if (cell == f->tail)
422 f->tail = cell->next;
423 f->cells--;
424
425 /* add cell to free list */
426 cell->next = NULL;
427 if (freefirst == NULL) {
428 freefirst = cell;
429 } else {
430 freeprev->next = cell;
431 }
432
433 freeprev = cell;
434 } else {
435 prev = cell;
436 }
437 cell = next;
438 }
439 spin_unlock_irqrestore(&f->lock, flags);
440
441 /* remove selected cells */
442 while (freefirst) {
443 freenext = freefirst->next;
444 snd_seq_cell_free(freefirst);
445 freefirst = freenext;
446 }
447}
448
449
diff --git a/sound/core/seq/seq_prioq.h b/sound/core/seq/seq_prioq.h
new file mode 100644
index 000000000000..f12af79308b8
--- /dev/null
+++ b/sound/core/seq/seq_prioq.h
@@ -0,0 +1,62 @@
1/*
2 * ALSA sequencer Priority Queue
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_PRIOQ_H
22#define __SND_SEQ_PRIOQ_H
23
24#include "seq_memory.h"
25
26
27/* === PRIOQ === */
28
29typedef struct {
30 snd_seq_event_cell_t* head; /* pointer to head of prioq */
31 snd_seq_event_cell_t* tail; /* pointer to tail of prioq */
32 int cells;
33 spinlock_t lock;
34} prioq_t;
35
36
37/* create new prioq (constructor) */
38extern prioq_t *snd_seq_prioq_new(void);
39
40/* delete prioq (destructor) */
41extern void snd_seq_prioq_delete(prioq_t **fifo);
42
43/* enqueue cell to prioq */
44extern int snd_seq_prioq_cell_in(prioq_t *f, snd_seq_event_cell_t *cell);
45
46/* dequeue cell from prioq */
47extern snd_seq_event_cell_t *snd_seq_prioq_cell_out(prioq_t *f);
48
49/* return number of events available in prioq */
50extern int snd_seq_prioq_avail(prioq_t *f);
51
52/* peek at cell at the head of the prioq */
53extern snd_seq_event_cell_t *snd_seq_prioq_cell_peek(prioq_t *f);
54
55/* client left queue */
56extern void snd_seq_prioq_leave(prioq_t *f, int client, int timestamp);
57
58/* Remove events */
59void snd_seq_prioq_remove_events(prioq_t * f, int client,
60 snd_seq_remove_events_t *info);
61
62#endif
diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c
new file mode 100644
index 000000000000..3afc7cc0c9a7
--- /dev/null
+++ b/sound/core/seq/seq_queue.c
@@ -0,0 +1,783 @@
1/*
2 * ALSA sequencer Timing queue handling
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * MAJOR CHANGES
20 * Nov. 13, 1999 Takashi Iwai <iwai@ww.uni-erlangen.de>
21 * - Queues are allocated dynamically via ioctl.
22 * - When owner client is deleted, all owned queues are deleted, too.
23 * - Owner of unlocked queue is kept unmodified even if it is
24 * manipulated by other clients.
25 * - Owner field in SET_QUEUE_OWNER ioctl must be identical with the
26 * caller client. i.e. Changing owner to a third client is not
27 * allowed.
28 *
29 * Aug. 30, 2000 Takashi Iwai
30 * - Queues are managed in static array again, but with better way.
31 * The API itself is identical.
32 * - The queue is locked when queue_t pinter is returned via
33 * queueptr(). This pointer *MUST* be released afterward by
34 * queuefree(ptr).
35 * - Addition of experimental sync support.
36 */
37
38#include <sound/driver.h>
39#include <linux/init.h>
40#include <linux/slab.h>
41#include <sound/core.h>
42
43#include "seq_memory.h"
44#include "seq_queue.h"
45#include "seq_clientmgr.h"
46#include "seq_fifo.h"
47#include "seq_timer.h"
48#include "seq_info.h"
49
50/* list of allocated queues */
51static queue_t *queue_list[SNDRV_SEQ_MAX_QUEUES];
52static DEFINE_SPINLOCK(queue_list_lock);
53/* number of queues allocated */
54static int num_queues;
55
56int snd_seq_queue_get_cur_queues(void)
57{
58 return num_queues;
59}
60
61/*----------------------------------------------------------------*/
62
63/* assign queue id and insert to list */
64static int queue_list_add(queue_t *q)
65{
66 int i;
67 unsigned long flags;
68
69 spin_lock_irqsave(&queue_list_lock, flags);
70 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
71 if (! queue_list[i]) {
72 queue_list[i] = q;
73 q->queue = i;
74 num_queues++;
75 spin_unlock_irqrestore(&queue_list_lock, flags);
76 return i;
77 }
78 }
79 spin_unlock_irqrestore(&queue_list_lock, flags);
80 return -1;
81}
82
83static queue_t *queue_list_remove(int id, int client)
84{
85 queue_t *q;
86 unsigned long flags;
87
88 spin_lock_irqsave(&queue_list_lock, flags);
89 q = queue_list[id];
90 if (q) {
91 spin_lock(&q->owner_lock);
92 if (q->owner == client) {
93 /* found */
94 q->klocked = 1;
95 spin_unlock(&q->owner_lock);
96 queue_list[id] = NULL;
97 num_queues--;
98 spin_unlock_irqrestore(&queue_list_lock, flags);
99 return q;
100 }
101 spin_unlock(&q->owner_lock);
102 }
103 spin_unlock_irqrestore(&queue_list_lock, flags);
104 return NULL;
105}
106
107/*----------------------------------------------------------------*/
108
109/* create new queue (constructor) */
110static queue_t *queue_new(int owner, int locked)
111{
112 queue_t *q;
113
114 q = kcalloc(1, sizeof(*q), GFP_KERNEL);
115 if (q == NULL) {
116 snd_printd("malloc failed for snd_seq_queue_new()\n");
117 return NULL;
118 }
119
120 spin_lock_init(&q->owner_lock);
121 spin_lock_init(&q->check_lock);
122 init_MUTEX(&q->timer_mutex);
123 snd_use_lock_init(&q->use_lock);
124 q->queue = -1;
125
126 q->tickq = snd_seq_prioq_new();
127 q->timeq = snd_seq_prioq_new();
128 q->timer = snd_seq_timer_new();
129 if (q->tickq == NULL || q->timeq == NULL || q->timer == NULL) {
130 snd_seq_prioq_delete(&q->tickq);
131 snd_seq_prioq_delete(&q->timeq);
132 snd_seq_timer_delete(&q->timer);
133 kfree(q);
134 return NULL;
135 }
136
137 q->owner = owner;
138 q->locked = locked;
139 q->klocked = 0;
140
141 return q;
142}
143
144/* delete queue (destructor) */
145static void queue_delete(queue_t *q)
146{
147 /* stop and release the timer */
148 snd_seq_timer_stop(q->timer);
149 snd_seq_timer_close(q);
150 /* wait until access free */
151 snd_use_lock_sync(&q->use_lock);
152 /* release resources... */
153 snd_seq_prioq_delete(&q->tickq);
154 snd_seq_prioq_delete(&q->timeq);
155 snd_seq_timer_delete(&q->timer);
156
157 kfree(q);
158}
159
160
161/*----------------------------------------------------------------*/
162
163/* setup queues */
164int __init snd_seq_queues_init(void)
165{
166 /*
167 memset(queue_list, 0, sizeof(queue_list));
168 num_queues = 0;
169 */
170 return 0;
171}
172
173/* delete all existing queues */
174void __exit snd_seq_queues_delete(void)
175{
176 int i;
177
178 /* clear list */
179 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
180 if (queue_list[i])
181 queue_delete(queue_list[i]);
182 }
183}
184
185/* allocate a new queue -
186 * return queue index value or negative value for error
187 */
188int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
189{
190 queue_t *q;
191
192 q = queue_new(client, locked);
193 if (q == NULL)
194 return -ENOMEM;
195 q->info_flags = info_flags;
196 if (queue_list_add(q) < 0) {
197 queue_delete(q);
198 return -ENOMEM;
199 }
200 snd_seq_queue_use(q->queue, client, 1); /* use this queue */
201 return q->queue;
202}
203
204/* delete a queue - queue must be owned by the client */
205int snd_seq_queue_delete(int client, int queueid)
206{
207 queue_t *q;
208
209 if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
210 return -EINVAL;
211 q = queue_list_remove(queueid, client);
212 if (q == NULL)
213 return -EINVAL;
214 queue_delete(q);
215
216 return 0;
217}
218
219
220/* return pointer to queue structure for specified id */
221queue_t *queueptr(int queueid)
222{
223 queue_t *q;
224 unsigned long flags;
225
226 if (queueid < 0 || queueid >= SNDRV_SEQ_MAX_QUEUES)
227 return NULL;
228 spin_lock_irqsave(&queue_list_lock, flags);
229 q = queue_list[queueid];
230 if (q)
231 snd_use_lock_use(&q->use_lock);
232 spin_unlock_irqrestore(&queue_list_lock, flags);
233 return q;
234}
235
236/* return the (first) queue matching with the specified name */
237queue_t *snd_seq_queue_find_name(char *name)
238{
239 int i;
240 queue_t *q;
241
242 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
243 if ((q = queueptr(i)) != NULL) {
244 if (strncmp(q->name, name, sizeof(q->name)) == 0)
245 return q;
246 queuefree(q);
247 }
248 }
249 return NULL;
250}
251
252
253/* -------------------------------------------------------- */
254
255void snd_seq_check_queue(queue_t *q, int atomic, int hop)
256{
257 unsigned long flags;
258 snd_seq_event_cell_t *cell;
259
260 if (q == NULL)
261 return;
262
263 /* make this function non-reentrant */
264 spin_lock_irqsave(&q->check_lock, flags);
265 if (q->check_blocked) {
266 q->check_again = 1;
267 spin_unlock_irqrestore(&q->check_lock, flags);
268 return; /* other thread is already checking queues */
269 }
270 q->check_blocked = 1;
271 spin_unlock_irqrestore(&q->check_lock, flags);
272
273 __again:
274 /* Process tick queue... */
275 while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) {
276 if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick, &cell->event.time.tick)) {
277 cell = snd_seq_prioq_cell_out(q->tickq);
278 if (cell)
279 snd_seq_dispatch_event(cell, atomic, hop);
280 } else {
281 /* event remains in the queue */
282 break;
283 }
284 }
285
286
287 /* Process time queue... */
288 while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) {
289 if (snd_seq_compare_real_time(&q->timer->cur_time, &cell->event.time.time)) {
290 cell = snd_seq_prioq_cell_out(q->timeq);
291 if (cell)
292 snd_seq_dispatch_event(cell, atomic, hop);
293 } else {
294 /* event remains in the queue */
295 break;
296 }
297 }
298
299 /* free lock */
300 spin_lock_irqsave(&q->check_lock, flags);
301 if (q->check_again) {
302 q->check_again = 0;
303 spin_unlock_irqrestore(&q->check_lock, flags);
304 goto __again;
305 }
306 q->check_blocked = 0;
307 spin_unlock_irqrestore(&q->check_lock, flags);
308}
309
310
311/* enqueue a event to singe queue */
312int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop)
313{
314 int dest, err;
315 queue_t *q;
316
317 snd_assert(cell != NULL, return -EINVAL);
318 dest = cell->event.queue; /* destination queue */
319 q = queueptr(dest);
320 if (q == NULL)
321 return -EINVAL;
322 /* handle relative time stamps, convert them into absolute */
323 if ((cell->event.flags & SNDRV_SEQ_TIME_MODE_MASK) == SNDRV_SEQ_TIME_MODE_REL) {
324 switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
325 case SNDRV_SEQ_TIME_STAMP_TICK:
326 cell->event.time.tick += q->timer->tick.cur_tick;
327 break;
328
329 case SNDRV_SEQ_TIME_STAMP_REAL:
330 snd_seq_inc_real_time(&cell->event.time.time, &q->timer->cur_time);
331 break;
332 }
333 cell->event.flags &= ~SNDRV_SEQ_TIME_MODE_MASK;
334 cell->event.flags |= SNDRV_SEQ_TIME_MODE_ABS;
335 }
336 /* enqueue event in the real-time or midi queue */
337 switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
338 case SNDRV_SEQ_TIME_STAMP_TICK:
339 err = snd_seq_prioq_cell_in(q->tickq, cell);
340 break;
341
342 case SNDRV_SEQ_TIME_STAMP_REAL:
343 default:
344 err = snd_seq_prioq_cell_in(q->timeq, cell);
345 break;
346 }
347
348 if (err < 0) {
349 queuefree(q); /* unlock */
350 return err;
351 }
352
353 /* trigger dispatching */
354 snd_seq_check_queue(q, atomic, hop);
355
356 queuefree(q); /* unlock */
357
358 return 0;
359}
360
361
362/*----------------------------------------------------------------*/
363
364static inline int check_access(queue_t *q, int client)
365{
366 return (q->owner == client) || (!q->locked && !q->klocked);
367}
368
369/* check if the client has permission to modify queue parameters.
370 * if it does, lock the queue
371 */
372static int queue_access_lock(queue_t *q, int client)
373{
374 unsigned long flags;
375 int access_ok;
376
377 spin_lock_irqsave(&q->owner_lock, flags);
378 access_ok = check_access(q, client);
379 if (access_ok)
380 q->klocked = 1;
381 spin_unlock_irqrestore(&q->owner_lock, flags);
382 return access_ok;
383}
384
385/* unlock the queue */
386static inline void queue_access_unlock(queue_t *q)
387{
388 unsigned long flags;
389
390 spin_lock_irqsave(&q->owner_lock, flags);
391 q->klocked = 0;
392 spin_unlock_irqrestore(&q->owner_lock, flags);
393}
394
395/* exported - only checking permission */
396int snd_seq_queue_check_access(int queueid, int client)
397{
398 queue_t *q = queueptr(queueid);
399 int access_ok;
400 unsigned long flags;
401
402 if (! q)
403 return 0;
404 spin_lock_irqsave(&q->owner_lock, flags);
405 access_ok = check_access(q, client);
406 spin_unlock_irqrestore(&q->owner_lock, flags);
407 queuefree(q);
408 return access_ok;
409}
410
411/*----------------------------------------------------------------*/
412
413/*
414 * change queue's owner and permission
415 */
416int snd_seq_queue_set_owner(int queueid, int client, int locked)
417{
418 queue_t *q = queueptr(queueid);
419
420 if (q == NULL)
421 return -EINVAL;
422
423 if (! queue_access_lock(q, client)) {
424 queuefree(q);
425 return -EPERM;
426 }
427
428 q->locked = locked ? 1 : 0;
429 q->owner = client;
430 queue_access_unlock(q);
431 queuefree(q);
432
433 return 0;
434}
435
436
437/*----------------------------------------------------------------*/
438
439/* open timer -
440 * q->use mutex should be down before calling this function to avoid
441 * confliction with snd_seq_queue_use()
442 */
443int snd_seq_queue_timer_open(int queueid)
444{
445 int result = 0;
446 queue_t *queue;
447 seq_timer_t *tmr;
448
449 queue = queueptr(queueid);
450 if (queue == NULL)
451 return -EINVAL;
452 tmr = queue->timer;
453 if ((result = snd_seq_timer_open(queue)) < 0) {
454 snd_seq_timer_defaults(tmr);
455 result = snd_seq_timer_open(queue);
456 }
457 queuefree(queue);
458 return result;
459}
460
461/* close timer -
462 * q->use mutex should be down before calling this function
463 */
464int snd_seq_queue_timer_close(int queueid)
465{
466 queue_t *queue;
467 seq_timer_t *tmr;
468 int result = 0;
469
470 queue = queueptr(queueid);
471 if (queue == NULL)
472 return -EINVAL;
473 tmr = queue->timer;
474 snd_seq_timer_close(queue);
475 queuefree(queue);
476 return result;
477}
478
479/* change queue tempo and ppq */
480int snd_seq_queue_timer_set_tempo(int queueid, int client, snd_seq_queue_tempo_t *info)
481{
482 queue_t *q = queueptr(queueid);
483 int result;
484
485 if (q == NULL)
486 return -EINVAL;
487 if (! queue_access_lock(q, client)) {
488 queuefree(q);
489 return -EPERM;
490 }
491
492 result = snd_seq_timer_set_tempo(q->timer, info->tempo);
493 if (result >= 0)
494 result = snd_seq_timer_set_ppq(q->timer, info->ppq);
495 if (result >= 0 && info->skew_base > 0)
496 result = snd_seq_timer_set_skew(q->timer, info->skew_value, info->skew_base);
497 queue_access_unlock(q);
498 queuefree(q);
499 return result;
500}
501
502
503/* use or unuse this queue -
504 * if it is the first client, starts the timer.
505 * if it is not longer used by any clients, stop the timer.
506 */
507int snd_seq_queue_use(int queueid, int client, int use)
508{
509 queue_t *queue;
510
511 queue = queueptr(queueid);
512 if (queue == NULL)
513 return -EINVAL;
514 down(&queue->timer_mutex);
515 if (use) {
516 if (!test_and_set_bit(client, queue->clients_bitmap))
517 queue->clients++;
518 } else {
519 if (test_and_clear_bit(client, queue->clients_bitmap))
520 queue->clients--;
521 }
522 if (queue->clients) {
523 if (use && queue->clients == 1)
524 snd_seq_timer_defaults(queue->timer);
525 snd_seq_timer_open(queue);
526 } else {
527 snd_seq_timer_close(queue);
528 }
529 up(&queue->timer_mutex);
530 queuefree(queue);
531 return 0;
532}
533
534/*
535 * check if queue is used by the client
536 * return negative value if the queue is invalid.
537 * return 0 if not used, 1 if used.
538 */
539int snd_seq_queue_is_used(int queueid, int client)
540{
541 queue_t *q;
542 int result;
543
544 q = queueptr(queueid);
545 if (q == NULL)
546 return -EINVAL; /* invalid queue */
547 result = test_bit(client, q->clients_bitmap) ? 1 : 0;
548 queuefree(q);
549 return result;
550}
551
552
553/*----------------------------------------------------------------*/
554
555/* notification that client has left the system -
556 * stop the timer on all queues owned by this client
557 */
558void snd_seq_queue_client_termination(int client)
559{
560 unsigned long flags;
561 int i;
562 queue_t *q;
563
564 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
565 if ((q = queueptr(i)) == NULL)
566 continue;
567 spin_lock_irqsave(&q->owner_lock, flags);
568 if (q->owner == client)
569 q->klocked = 1;
570 spin_unlock_irqrestore(&q->owner_lock, flags);
571 if (q->owner == client) {
572 if (q->timer->running)
573 snd_seq_timer_stop(q->timer);
574 snd_seq_timer_reset(q->timer);
575 }
576 queuefree(q);
577 }
578}
579
580/* final stage notification -
581 * remove cells for no longer exist client (for non-owned queue)
582 * or delete this queue (for owned queue)
583 */
584void snd_seq_queue_client_leave(int client)
585{
586 int i;
587 queue_t *q;
588
589 /* delete own queues from queue list */
590 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
591 if ((q = queue_list_remove(i, client)) != NULL)
592 queue_delete(q);
593 }
594
595 /* remove cells from existing queues -
596 * they are not owned by this client
597 */
598 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
599 if ((q = queueptr(i)) == NULL)
600 continue;
601 if (test_bit(client, q->clients_bitmap)) {
602 snd_seq_prioq_leave(q->tickq, client, 0);
603 snd_seq_prioq_leave(q->timeq, client, 0);
604 snd_seq_queue_use(q->queue, client, 0);
605 }
606 queuefree(q);
607 }
608}
609
610
611
612/*----------------------------------------------------------------*/
613
614/* remove cells from all queues */
615void snd_seq_queue_client_leave_cells(int client)
616{
617 int i;
618 queue_t *q;
619
620 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
621 if ((q = queueptr(i)) == NULL)
622 continue;
623 snd_seq_prioq_leave(q->tickq, client, 0);
624 snd_seq_prioq_leave(q->timeq, client, 0);
625 queuefree(q);
626 }
627}
628
629/* remove cells based on flush criteria */
630void snd_seq_queue_remove_cells(int client, snd_seq_remove_events_t *info)
631{
632 int i;
633 queue_t *q;
634
635 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
636 if ((q = queueptr(i)) == NULL)
637 continue;
638 if (test_bit(client, q->clients_bitmap) &&
639 (! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) ||
640 q->queue == info->queue)) {
641 snd_seq_prioq_remove_events(q->tickq, client, info);
642 snd_seq_prioq_remove_events(q->timeq, client, info);
643 }
644 queuefree(q);
645 }
646}
647
648/*----------------------------------------------------------------*/
649
650/*
651 * send events to all subscribed ports
652 */
653static void queue_broadcast_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop)
654{
655 snd_seq_event_t sev;
656
657 sev = *ev;
658
659 sev.flags = SNDRV_SEQ_TIME_STAMP_TICK|SNDRV_SEQ_TIME_MODE_ABS;
660 sev.time.tick = q->timer->tick.cur_tick;
661 sev.queue = q->queue;
662 sev.data.queue.queue = q->queue;
663
664 /* broadcast events from Timer port */
665 sev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
666 sev.source.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
667 sev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
668 snd_seq_kernel_client_dispatch(SNDRV_SEQ_CLIENT_SYSTEM, &sev, atomic, hop);
669}
670
671/*
672 * process a received queue-control event.
673 * this function is exported for seq_sync.c.
674 */
675void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop)
676{
677 switch (ev->type) {
678 case SNDRV_SEQ_EVENT_START:
679 snd_seq_prioq_leave(q->tickq, ev->source.client, 1);
680 snd_seq_prioq_leave(q->timeq, ev->source.client, 1);
681 if (! snd_seq_timer_start(q->timer))
682 queue_broadcast_event(q, ev, atomic, hop);
683 break;
684
685 case SNDRV_SEQ_EVENT_CONTINUE:
686 if (! snd_seq_timer_continue(q->timer))
687 queue_broadcast_event(q, ev, atomic, hop);
688 break;
689
690 case SNDRV_SEQ_EVENT_STOP:
691 snd_seq_timer_stop(q->timer);
692 queue_broadcast_event(q, ev, atomic, hop);
693 break;
694
695 case SNDRV_SEQ_EVENT_TEMPO:
696 snd_seq_timer_set_tempo(q->timer, ev->data.queue.param.value);
697 queue_broadcast_event(q, ev, atomic, hop);
698 break;
699
700 case SNDRV_SEQ_EVENT_SETPOS_TICK:
701 if (snd_seq_timer_set_position_tick(q->timer, ev->data.queue.param.time.tick) == 0) {
702 queue_broadcast_event(q, ev, atomic, hop);
703 }
704 break;
705
706 case SNDRV_SEQ_EVENT_SETPOS_TIME:
707 if (snd_seq_timer_set_position_time(q->timer, ev->data.queue.param.time.time) == 0) {
708 queue_broadcast_event(q, ev, atomic, hop);
709 }
710 break;
711 case SNDRV_SEQ_EVENT_QUEUE_SKEW:
712 if (snd_seq_timer_set_skew(q->timer,
713 ev->data.queue.param.skew.value,
714 ev->data.queue.param.skew.base) == 0) {
715 queue_broadcast_event(q, ev, atomic, hop);
716 }
717 break;
718 }
719}
720
721
722/*
723 * Queue control via timer control port:
724 * this function is exported as a callback of timer port.
725 */
726int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop)
727{
728 queue_t *q;
729
730 snd_assert(ev != NULL, return -EINVAL);
731 q = queueptr(ev->data.queue.queue);
732
733 if (q == NULL)
734 return -EINVAL;
735
736 if (! queue_access_lock(q, ev->source.client)) {
737 queuefree(q);
738 return -EPERM;
739 }
740
741 snd_seq_queue_process_event(q, ev, atomic, hop);
742
743 queue_access_unlock(q);
744 queuefree(q);
745 return 0;
746}
747
748
749/*----------------------------------------------------------------*/
750
751/* exported to seq_info.c */
752void snd_seq_info_queues_read(snd_info_entry_t *entry,
753 snd_info_buffer_t * buffer)
754{
755 int i, bpm;
756 queue_t *q;
757 seq_timer_t *tmr;
758
759 for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
760 if ((q = queueptr(i)) == NULL)
761 continue;
762
763 tmr = q->timer;
764 if (tmr->tempo)
765 bpm = 60000000 / tmr->tempo;
766 else
767 bpm = 0;
768
769 snd_iprintf(buffer, "queue %d: [%s]\n", q->queue, q->name);
770 snd_iprintf(buffer, "owned by client : %d\n", q->owner);
771 snd_iprintf(buffer, "lock status : %s\n", q->locked ? "Locked" : "Free");
772 snd_iprintf(buffer, "queued time events : %d\n", snd_seq_prioq_avail(q->timeq));
773 snd_iprintf(buffer, "queued tick events : %d\n", snd_seq_prioq_avail(q->tickq));
774 snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped");
775 snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq);
776 snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo);
777 snd_iprintf(buffer, "current BPM : %d\n", bpm);
778 snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec);
779 snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick);
780 snd_iprintf(buffer, "\n");
781 queuefree(q);
782 }
783}
diff --git a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h
new file mode 100644
index 000000000000..b1bf5519fb3b
--- /dev/null
+++ b/sound/core/seq/seq_queue.h
@@ -0,0 +1,140 @@
1/*
2 * ALSA sequencer Queue handling
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20#ifndef __SND_SEQ_QUEUE_H
21#define __SND_SEQ_QUEUE_H
22
23#include "seq_memory.h"
24#include "seq_prioq.h"
25#include "seq_timer.h"
26#include "seq_lock.h"
27#include <linux/interrupt.h>
28#include <linux/list.h>
29#include <linux/bitops.h>
30
31#define SEQ_QUEUE_NO_OWNER (-1)
32
33struct _snd_seq_queue {
34 int queue; /* queue number */
35
36 char name[64]; /* name of this queue */
37
38 prioq_t *tickq; /* midi tick event queue */
39 prioq_t *timeq; /* real-time event queue */
40
41 seq_timer_t *timer; /* time keeper for this queue */
42 int owner; /* client that 'owns' the timer */
43 unsigned int locked:1, /* timer is only accesibble by owner if set */
44 klocked:1, /* kernel lock (after START) */
45 check_again:1,
46 check_blocked:1;
47
48 unsigned int flags; /* status flags */
49 unsigned int info_flags; /* info for sync */
50
51 spinlock_t owner_lock;
52 spinlock_t check_lock;
53
54 /* clients which uses this queue (bitmap) */
55 DECLARE_BITMAP(clients_bitmap, SNDRV_SEQ_MAX_CLIENTS);
56 unsigned int clients; /* users of this queue */
57 struct semaphore timer_mutex;
58
59 snd_use_lock_t use_lock;
60};
61
62
63/* get the number of current queues */
64int snd_seq_queue_get_cur_queues(void);
65
66/* init queues structure */
67int snd_seq_queues_init(void);
68
69/* delete queues */
70void snd_seq_queues_delete(void);
71
72
73/* create new queue (constructor) */
74int snd_seq_queue_alloc(int client, int locked, unsigned int flags);
75
76/* delete queue (destructor) */
77int snd_seq_queue_delete(int client, int queueid);
78
79/* notification that client has left the system */
80void snd_seq_queue_client_termination(int client);
81
82/* final stage */
83void snd_seq_queue_client_leave(int client);
84
85/* enqueue a event received from one the clients */
86int snd_seq_enqueue_event(snd_seq_event_cell_t *cell, int atomic, int hop);
87
88/* Remove events */
89void snd_seq_queue_client_leave_cells(int client);
90void snd_seq_queue_remove_cells(int client, snd_seq_remove_events_t *info);
91
92/* return pointer to queue structure for specified id */
93queue_t *queueptr(int queueid);
94/* unlock */
95#define queuefree(q) snd_use_lock_free(&(q)->use_lock)
96
97/* return the (first) queue matching with the specified name */
98queue_t *snd_seq_queue_find_name(char *name);
99
100/* check single queue and dispatch events */
101void snd_seq_check_queue(queue_t *q, int atomic, int hop);
102
103/* access to queue's parameters */
104int snd_seq_queue_check_access(int queueid, int client);
105int snd_seq_queue_timer_set_tempo(int queueid, int client, snd_seq_queue_tempo_t *info);
106int snd_seq_queue_set_owner(int queueid, int client, int locked);
107int snd_seq_queue_set_locked(int queueid, int client, int locked);
108int snd_seq_queue_timer_open(int queueid);
109int snd_seq_queue_timer_close(int queueid);
110int snd_seq_queue_use(int queueid, int client, int use);
111int snd_seq_queue_is_used(int queueid, int client);
112
113int snd_seq_control_queue(snd_seq_event_t *ev, int atomic, int hop);
114void snd_seq_queue_process_event(queue_t *q, snd_seq_event_t *ev, int atomic, int hop);
115
116/*
117 * 64bit division - for sync stuff..
118 */
119#if defined(i386) || defined(i486)
120
121#define udiv_qrnnd(q, r, n1, n0, d) \
122 __asm__ ("divl %4" \
123 : "=a" ((u32)(q)), \
124 "=d" ((u32)(r)) \
125 : "0" ((u32)(n0)), \
126 "1" ((u32)(n1)), \
127 "rm" ((u32)(d)))
128
129#define u64_div(x,y,q) do {u32 __tmp; udiv_qrnnd(q, __tmp, (x)>>32, x, y);} while (0)
130#define u64_mod(x,y,r) do {u32 __tmp; udiv_qrnnd(__tmp, q, (x)>>32, x, y);} while (0)
131#define u64_divmod(x,y,q,r) udiv_qrnnd(q, r, (x)>>32, x, y)
132
133#else
134#define u64_div(x,y,q) ((q) = (u32)((u64)(x) / (u64)(y)))
135#define u64_mod(x,y,r) ((r) = (u32)((u64)(x) % (u64)(y)))
136#define u64_divmod(x,y,q,r) (u64_div(x,y,q), u64_mod(x,y,r))
137#endif
138
139
140#endif
diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c
new file mode 100644
index 000000000000..e8f0a6683d50
--- /dev/null
+++ b/sound/core/seq/seq_system.c
@@ -0,0 +1,190 @@
1/*
2 * ALSA sequencer System services Client
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
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 <sound/core.h>
25#include "seq_system.h"
26#include "seq_timer.h"
27#include "seq_queue.h"
28
29/* internal client that provide system services, access to timer etc. */
30
31/*
32 * Port "Timer"
33 * - send tempo /start/stop etc. events to this port to manipulate the
34 * queue's timer. The queue address is specified in
35 * data.queue.queue.
36 * - this port supports subscription. The received timer events are
37 * broadcasted to all subscribed clients. The modified tempo
38 * value is stored on data.queue.value.
39 * The modifier client/port is not send.
40 *
41 * Port "Announce"
42 * - does not receive message
43 * - supports supscription. For each client or port attaching to or
44 * detaching from the system an announcement is send to the subscribed
45 * clients.
46 *
47 * Idea: the subscription mechanism might also work handy for distributing
48 * synchronisation and timing information. In this case we would ideally have
49 * a list of subscribers for each type of sync (time, tick), for each timing
50 * queue.
51 *
52 * NOTE: the queue to be started, stopped, etc. must be specified
53 * in data.queue.addr.queue field. queue is used only for
54 * scheduling, and no longer referred as affected queue.
55 * They are used only for timer broadcast (see above).
56 * -- iwai
57 */
58
59
60/* client id of our system client */
61static int sysclient = -1;
62
63/* port id numbers for this client */
64static int announce_port = -1;
65
66
67
68/* fill standard header data, source port & channel are filled in */
69static int setheader(snd_seq_event_t * ev, int client, int port)
70{
71 if (announce_port < 0)
72 return -ENODEV;
73
74 memset(ev, 0, sizeof(snd_seq_event_t));
75
76 ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
77 ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED;
78
79 ev->source.client = sysclient;
80 ev->source.port = announce_port;
81 ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
82
83 /* fill data */
84 /*ev->data.addr.queue = SNDRV_SEQ_ADDRESS_UNKNOWN;*/
85 ev->data.addr.client = client;
86 ev->data.addr.port = port;
87
88 return 0;
89}
90
91
92/* entry points for broadcasting system events */
93void snd_seq_system_broadcast(int client, int port, int type)
94{
95 snd_seq_event_t ev;
96
97 if (setheader(&ev, client, port) < 0)
98 return;
99 ev.type = type;
100 snd_seq_kernel_client_dispatch(sysclient, &ev, 0, 0);
101}
102
103/* entry points for broadcasting system events */
104int snd_seq_system_notify(int client, int port, snd_seq_event_t *ev)
105{
106 ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
107 ev->source.client = sysclient;
108 ev->source.port = announce_port;
109 ev->dest.client = client;
110 ev->dest.port = port;
111 return snd_seq_kernel_client_dispatch(sysclient, ev, 0, 0);
112}
113
114/* call-back handler for timer events */
115static int event_input_timer(snd_seq_event_t * ev, int direct, void *private_data, int atomic, int hop)
116{
117 return snd_seq_control_queue(ev, atomic, hop);
118}
119
120/* register our internal client */
121int __init snd_seq_system_client_init(void)
122{
123
124 snd_seq_client_callback_t callbacks;
125 snd_seq_port_callback_t pcallbacks;
126 snd_seq_client_info_t *inf;
127 snd_seq_port_info_t *port;
128
129 inf = kcalloc(1, sizeof(*inf), GFP_KERNEL);
130 port = kcalloc(1, sizeof(*port), GFP_KERNEL);
131 if (! inf || ! port) {
132 kfree(inf);
133 kfree(port);
134 return -ENOMEM;
135 }
136
137 memset(&callbacks, 0, sizeof(callbacks));
138 memset(&pcallbacks, 0, sizeof(pcallbacks));
139 pcallbacks.owner = THIS_MODULE;
140 pcallbacks.event_input = event_input_timer;
141
142 /* register client */
143 callbacks.allow_input = callbacks.allow_output = 1;
144 sysclient = snd_seq_create_kernel_client(NULL, 0, &callbacks);
145
146 /* set our name */
147 inf->client = 0;
148 inf->type = KERNEL_CLIENT;
149 strcpy(inf->name, "System");
150 snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, inf);
151
152 /* register timer */
153 strcpy(port->name, "Timer");
154 port->capability = SNDRV_SEQ_PORT_CAP_WRITE; /* accept queue control */
155 port->capability |= SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast */
156 port->kernel = &pcallbacks;
157 port->type = 0;
158 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
159 port->addr.client = sysclient;
160 port->addr.port = SNDRV_SEQ_PORT_SYSTEM_TIMER;
161 snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
162
163 /* register announcement port */
164 strcpy(port->name, "Announce");
165 port->capability = SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ; /* for broadcast only */
166 port->kernel = NULL;
167 port->type = 0;
168 port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
169 port->addr.client = sysclient;
170 port->addr.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
171 snd_seq_kernel_client_ctl(sysclient, SNDRV_SEQ_IOCTL_CREATE_PORT, port);
172 announce_port = port->addr.port;
173
174 kfree(inf);
175 kfree(port);
176 return 0;
177}
178
179
180/* unregister our internal client */
181void __exit snd_seq_system_client_done(void)
182{
183 int oldsysclient = sysclient;
184
185 if (oldsysclient >= 0) {
186 sysclient = -1;
187 announce_port = -1;
188 snd_seq_delete_kernel_client(oldsysclient);
189 }
190}
diff --git a/sound/core/seq/seq_system.h b/sound/core/seq/seq_system.h
new file mode 100644
index 000000000000..900007255bb4
--- /dev/null
+++ b/sound/core/seq/seq_system.h
@@ -0,0 +1,46 @@
1/*
2 * ALSA sequencer System Client
3 * Copyright (c) 1998 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_SYSTEM_H
22#define __SND_SEQ_SYSTEM_H
23
24#include <sound/seq_kernel.h>
25
26
27/* entry points for broadcasting system events */
28void snd_seq_system_broadcast(int client, int port, int type);
29
30#define snd_seq_system_client_ev_client_start(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_START)
31#define snd_seq_system_client_ev_client_exit(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_EXIT)
32#define snd_seq_system_client_ev_client_change(client) snd_seq_system_broadcast(client, 0, SNDRV_SEQ_EVENT_CLIENT_CHANGE)
33#define snd_seq_system_client_ev_port_start(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_START)
34#define snd_seq_system_client_ev_port_exit(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_EXIT)
35#define snd_seq_system_client_ev_port_change(client, port) snd_seq_system_broadcast(client, port, SNDRV_SEQ_EVENT_PORT_CHANGE)
36
37int snd_seq_system_notify(int client, int port, snd_seq_event_t *ev);
38
39/* register our internal client */
40int snd_seq_system_client_init(void);
41
42/* unregister our internal client */
43void snd_seq_system_client_done(void);
44
45
46#endif
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
new file mode 100644
index 000000000000..753f1c0863cc
--- /dev/null
+++ b/sound/core/seq/seq_timer.c
@@ -0,0 +1,435 @@
1/*
2 * ALSA sequencer Timer
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
4 * Jaroslav Kysela <perex@suse.cz>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <sound/driver.h>
24#include <sound/core.h>
25#include <linux/slab.h>
26#include "seq_timer.h"
27#include "seq_queue.h"
28#include "seq_info.h"
29
30extern int seq_default_timer_class;
31extern int seq_default_timer_sclass;
32extern int seq_default_timer_card;
33extern int seq_default_timer_device;
34extern int seq_default_timer_subdevice;
35extern int seq_default_timer_resolution;
36
37#define SKEW_BASE 0x10000 /* 16bit shift */
38
39void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks)
40{
41 if (tempo < 1000000)
42 tick->resolution = (tempo * 1000) / ppq;
43 else {
44 /* might overflow.. */
45 unsigned int s;
46 s = tempo % ppq;
47 s = (s * 1000) / ppq;
48 tick->resolution = (tempo / ppq) * 1000;
49 tick->resolution += s;
50 }
51 if (tick->resolution <= 0)
52 tick->resolution = 1;
53 tick->resolution *= nticks;
54 snd_seq_timer_update_tick(tick, 0);
55}
56
57/* create new timer (constructor) */
58seq_timer_t *snd_seq_timer_new(void)
59{
60 seq_timer_t *tmr;
61
62 tmr = kcalloc(1, sizeof(*tmr), GFP_KERNEL);
63 if (tmr == NULL) {
64 snd_printd("malloc failed for snd_seq_timer_new() \n");
65 return NULL;
66 }
67 spin_lock_init(&tmr->lock);
68
69 /* reset setup to defaults */
70 snd_seq_timer_defaults(tmr);
71
72 /* reset time */
73 snd_seq_timer_reset(tmr);
74
75 return tmr;
76}
77
78/* delete timer (destructor) */
79void snd_seq_timer_delete(seq_timer_t **tmr)
80{
81 seq_timer_t *t = *tmr;
82 *tmr = NULL;
83
84 if (t == NULL) {
85 snd_printd("oops: snd_seq_timer_delete() called with NULL timer\n");
86 return;
87 }
88 t->running = 0;
89
90 /* reset time */
91 snd_seq_timer_stop(t);
92 snd_seq_timer_reset(t);
93
94 kfree(t);
95}
96
97void snd_seq_timer_defaults(seq_timer_t * tmr)
98{
99 /* setup defaults */
100 tmr->ppq = 96; /* 96 PPQ */
101 tmr->tempo = 500000; /* 120 BPM */
102 snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1);
103 tmr->running = 0;
104
105 tmr->type = SNDRV_SEQ_TIMER_ALSA;
106 tmr->alsa_id.dev_class = seq_default_timer_class;
107 tmr->alsa_id.dev_sclass = seq_default_timer_sclass;
108 tmr->alsa_id.card = seq_default_timer_card;
109 tmr->alsa_id.device = seq_default_timer_device;
110 tmr->alsa_id.subdevice = seq_default_timer_subdevice;
111 tmr->preferred_resolution = seq_default_timer_resolution;
112
113 tmr->skew = tmr->skew_base = SKEW_BASE;
114}
115
116void snd_seq_timer_reset(seq_timer_t * tmr)
117{
118 unsigned long flags;
119
120 spin_lock_irqsave(&tmr->lock, flags);
121
122 /* reset time & songposition */
123 tmr->cur_time.tv_sec = 0;
124 tmr->cur_time.tv_nsec = 0;
125
126 tmr->tick.cur_tick = 0;
127 tmr->tick.fraction = 0;
128
129 spin_unlock_irqrestore(&tmr->lock, flags);
130}
131
132
133/* called by timer interrupt routine. the period time since previous invocation is passed */
134static void snd_seq_timer_interrupt(snd_timer_instance_t *timeri,
135 unsigned long resolution,
136 unsigned long ticks)
137{
138 unsigned long flags;
139 queue_t *q = (queue_t *)timeri->callback_data;
140 seq_timer_t *tmr;
141
142 if (q == NULL)
143 return;
144 tmr = q->timer;
145 if (tmr == NULL)
146 return;
147 if (!tmr->running)
148 return;
149
150 resolution *= ticks;
151 if (tmr->skew != tmr->skew_base) {
152 /* FIXME: assuming skew_base = 0x10000 */
153 resolution = (resolution >> 16) * tmr->skew +
154 (((resolution & 0xffff) * tmr->skew) >> 16);
155 }
156
157 spin_lock_irqsave(&tmr->lock, flags);
158
159 /* update timer */
160 snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
161
162 /* calculate current tick */
163 snd_seq_timer_update_tick(&tmr->tick, resolution);
164
165 /* register actual time of this timer update */
166 do_gettimeofday(&tmr->last_update);
167
168 spin_unlock_irqrestore(&tmr->lock, flags);
169
170 /* check queues and dispatch events */
171 snd_seq_check_queue(q, 1, 0);
172}
173
174/* set current tempo */
175int snd_seq_timer_set_tempo(seq_timer_t * tmr, int tempo)
176{
177 unsigned long flags;
178
179 snd_assert(tmr, return -EINVAL);
180 if (tempo <= 0)
181 return -EINVAL;
182 spin_lock_irqsave(&tmr->lock, flags);
183 if ((unsigned int)tempo != tmr->tempo) {
184 tmr->tempo = tempo;
185 snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1);
186 }
187 spin_unlock_irqrestore(&tmr->lock, flags);
188 return 0;
189}
190
191/* set current ppq */
192int snd_seq_timer_set_ppq(seq_timer_t * tmr, int ppq)
193{
194 unsigned long flags;
195
196 snd_assert(tmr, return -EINVAL);
197 if (ppq <= 0)
198 return -EINVAL;
199 spin_lock_irqsave(&tmr->lock, flags);
200 if (tmr->running && (ppq != tmr->ppq)) {
201 /* refuse to change ppq on running timers */
202 /* because it will upset the song position (ticks) */
203 spin_unlock_irqrestore(&tmr->lock, flags);
204 snd_printd("seq: cannot change ppq of a running timer\n");
205 return -EBUSY;
206 }
207
208 tmr->ppq = ppq;
209 snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq, 1);
210 spin_unlock_irqrestore(&tmr->lock, flags);
211 return 0;
212}
213
214/* set current tick position */
215int snd_seq_timer_set_position_tick(seq_timer_t *tmr, snd_seq_tick_time_t position)
216{
217 unsigned long flags;
218
219 snd_assert(tmr, return -EINVAL);
220
221 spin_lock_irqsave(&tmr->lock, flags);
222 tmr->tick.cur_tick = position;
223 tmr->tick.fraction = 0;
224 spin_unlock_irqrestore(&tmr->lock, flags);
225 return 0;
226}
227
228/* set current real-time position */
229int snd_seq_timer_set_position_time(seq_timer_t *tmr, snd_seq_real_time_t position)
230{
231 unsigned long flags;
232
233 snd_assert(tmr, return -EINVAL);
234
235 snd_seq_sanity_real_time(&position);
236 spin_lock_irqsave(&tmr->lock, flags);
237 tmr->cur_time = position;
238 spin_unlock_irqrestore(&tmr->lock, flags);
239 return 0;
240}
241
242/* set timer skew */
243int snd_seq_timer_set_skew(seq_timer_t *tmr, unsigned int skew, unsigned int base)
244{
245 unsigned long flags;
246
247 snd_assert(tmr, return -EINVAL);
248
249 /* FIXME */
250 if (base != SKEW_BASE) {
251 snd_printd("invalid skew base 0x%x\n", base);
252 return -EINVAL;
253 }
254 spin_lock_irqsave(&tmr->lock, flags);
255 tmr->skew = skew;
256 spin_unlock_irqrestore(&tmr->lock, flags);
257 return 0;
258}
259
260int snd_seq_timer_open(queue_t *q)
261{
262 snd_timer_instance_t *t;
263 seq_timer_t *tmr;
264 char str[32];
265 int err;
266
267 tmr = q->timer;
268 snd_assert(tmr != NULL, return -EINVAL);
269 if (tmr->timeri)
270 return -EBUSY;
271 sprintf(str, "sequencer queue %i", q->queue);
272 if (tmr->type != SNDRV_SEQ_TIMER_ALSA) /* standard ALSA timer */
273 return -EINVAL;
274 if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
275 tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
276 err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue);
277 if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
278 if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
279 tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
280 snd_timer_id_t tid;
281 memset(&tid, 0, sizeof(tid));
282 tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
283 tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
284 tid.card = -1;
285 tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
286 err = snd_timer_open(&t, str, &tid, q->queue);
287 }
288 if (err < 0) {
289 snd_printk(KERN_ERR "seq fatal error: cannot create timer (%i)\n", err);
290 return err;
291 }
292 }
293 t->callback = snd_seq_timer_interrupt;
294 t->callback_data = q;
295 t->flags |= SNDRV_TIMER_IFLG_AUTO;
296 tmr->timeri = t;
297 return 0;
298}
299
300int snd_seq_timer_close(queue_t *q)
301{
302 seq_timer_t *tmr;
303
304 tmr = q->timer;
305 snd_assert(tmr != NULL, return -EINVAL);
306 if (tmr->timeri) {
307 snd_timer_stop(tmr->timeri);
308 snd_timer_close(tmr->timeri);
309 tmr->timeri = NULL;
310 }
311 return 0;
312}
313
314int snd_seq_timer_stop(seq_timer_t * tmr)
315{
316 if (! tmr->timeri)
317 return -EINVAL;
318 if (!tmr->running)
319 return 0;
320 tmr->running = 0;
321 snd_timer_pause(tmr->timeri);
322 return 0;
323}
324
325static int initialize_timer(seq_timer_t *tmr)
326{
327 snd_timer_t *t;
328 t = tmr->timeri->timer;
329 snd_assert(t, return -EINVAL);
330
331 tmr->ticks = 1;
332 if (tmr->preferred_resolution &&
333 ! (t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
334 unsigned long r = t->hw.resolution;
335 if (! r && t->hw.c_resolution)
336 r = t->hw.c_resolution(t);
337 if (r) {
338 tmr->ticks = (unsigned int)(1000000000uL / (r * tmr->preferred_resolution));
339 if (! tmr->ticks)
340 tmr->ticks = 1;
341 }
342 }
343 tmr->initialized = 1;
344 return 0;
345}
346
347int snd_seq_timer_start(seq_timer_t * tmr)
348{
349 if (! tmr->timeri)
350 return -EINVAL;
351 if (tmr->running)
352 snd_seq_timer_stop(tmr);
353 snd_seq_timer_reset(tmr);
354 if (initialize_timer(tmr) < 0)
355 return -EINVAL;
356 snd_timer_start(tmr->timeri, tmr->ticks);
357 tmr->running = 1;
358 do_gettimeofday(&tmr->last_update);
359 return 0;
360}
361
362int snd_seq_timer_continue(seq_timer_t * tmr)
363{
364 if (! tmr->timeri)
365 return -EINVAL;
366 if (tmr->running)
367 return -EBUSY;
368 if (! tmr->initialized) {
369 snd_seq_timer_reset(tmr);
370 if (initialize_timer(tmr) < 0)
371 return -EINVAL;
372 }
373 snd_timer_start(tmr->timeri, tmr->ticks);
374 tmr->running = 1;
375 do_gettimeofday(&tmr->last_update);
376 return 0;
377}
378
379/* return current 'real' time. use timeofday() to get better granularity. */
380snd_seq_real_time_t snd_seq_timer_get_cur_time(seq_timer_t *tmr)
381{
382 snd_seq_real_time_t cur_time;
383
384 cur_time = tmr->cur_time;
385 if (tmr->running) {
386 struct timeval tm;
387 int usec;
388 do_gettimeofday(&tm);
389 usec = (int)(tm.tv_usec - tmr->last_update.tv_usec);
390 if (usec < 0) {
391 cur_time.tv_nsec += (1000000 + usec) * 1000;
392 cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1;
393 } else {
394 cur_time.tv_nsec += usec * 1000;
395 cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec;
396 }
397 snd_seq_sanity_real_time(&cur_time);
398 }
399
400 return cur_time;
401}
402
403/* TODO: use interpolation on tick queue (will only be useful for very
404 high PPQ values) */
405snd_seq_tick_time_t snd_seq_timer_get_cur_tick(seq_timer_t *tmr)
406{
407 return tmr->tick.cur_tick;
408}
409
410
411/* exported to seq_info.c */
412void snd_seq_info_timer_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
413{
414 int idx;
415 queue_t *q;
416 seq_timer_t *tmr;
417 snd_timer_instance_t *ti;
418 unsigned long resolution;
419
420 for (idx = 0; idx < SNDRV_SEQ_MAX_QUEUES; idx++) {
421 q = queueptr(idx);
422 if (q == NULL)
423 continue;
424 if ((tmr = q->timer) == NULL ||
425 (ti = tmr->timeri) == NULL) {
426 queuefree(q);
427 continue;
428 }
429 snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
430 resolution = snd_timer_resolution(ti) * tmr->ticks;
431 snd_iprintf(buffer, " Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
432 snd_iprintf(buffer, " Skew : %u / %u\n", tmr->skew, tmr->skew_base);
433 queuefree(q);
434 }
435}
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h
new file mode 100644
index 000000000000..4c0872df8931
--- /dev/null
+++ b/sound/core/seq/seq_timer.h
@@ -0,0 +1,141 @@
1/*
2 * ALSA sequencer Timer
3 * Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
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#ifndef __SND_SEQ_TIMER_H
22#define __SND_SEQ_TIMER_H
23
24#include <sound/timer.h>
25#include <sound/seq_kernel.h>
26
27typedef struct {
28 snd_seq_tick_time_t cur_tick; /* current tick */
29 unsigned long resolution; /* time per tick in nsec */
30 unsigned long fraction; /* current time per tick in nsec */
31} seq_timer_tick_t;
32
33typedef struct {
34 /* ... tempo / offset / running state */
35
36 unsigned int running:1, /* running state of queue */
37 initialized:1; /* timer is initialized */
38
39 unsigned int tempo; /* current tempo, us/tick */
40 int ppq; /* time resolution, ticks/quarter */
41
42 snd_seq_real_time_t cur_time; /* current time */
43 seq_timer_tick_t tick; /* current tick */
44 int tick_updated;
45
46 int type; /* timer type */
47 snd_timer_id_t alsa_id; /* ALSA's timer ID */
48 snd_timer_instance_t *timeri; /* timer instance */
49 unsigned int ticks;
50 unsigned long preferred_resolution; /* timer resolution, ticks/sec */
51
52 unsigned int skew;
53 unsigned int skew_base;
54
55 struct timeval last_update; /* time of last clock update, used for interpolation */
56
57 spinlock_t lock;
58} seq_timer_t;
59
60
61/* create new timer (constructor) */
62extern seq_timer_t *snd_seq_timer_new(void);
63
64/* delete timer (destructor) */
65extern void snd_seq_timer_delete(seq_timer_t **tmr);
66
67void snd_seq_timer_set_tick_resolution(seq_timer_tick_t *tick, int tempo, int ppq, int nticks);
68
69/* */
70static inline void snd_seq_timer_update_tick(seq_timer_tick_t *tick, unsigned long resolution)
71{
72 if (tick->resolution > 0) {
73 tick->fraction += resolution;
74 tick->cur_tick += (unsigned int)(tick->fraction / tick->resolution);
75 tick->fraction %= tick->resolution;
76 }
77}
78
79
80/* compare timestamp between events */
81/* return 1 if a >= b; otherwise return 0 */
82static inline int snd_seq_compare_tick_time(snd_seq_tick_time_t *a, snd_seq_tick_time_t *b)
83{
84 /* compare ticks */
85 return (*a >= *b);
86}
87
88static inline int snd_seq_compare_real_time(snd_seq_real_time_t *a, snd_seq_real_time_t *b)
89{
90 /* compare real time */
91 if (a->tv_sec > b->tv_sec)
92 return 1;
93 if ((a->tv_sec == b->tv_sec) && (a->tv_nsec >= b->tv_nsec))
94 return 1;
95 return 0;
96}
97
98
99static inline void snd_seq_sanity_real_time(snd_seq_real_time_t *tm)
100{
101 while (tm->tv_nsec >= 1000000000) {
102 /* roll-over */
103 tm->tv_nsec -= 1000000000;
104 tm->tv_sec++;
105 }
106}
107
108
109/* increment timestamp */
110static inline void snd_seq_inc_real_time(snd_seq_real_time_t *tm, snd_seq_real_time_t *inc)
111{
112 tm->tv_sec += inc->tv_sec;
113 tm->tv_nsec += inc->tv_nsec;
114 snd_seq_sanity_real_time(tm);
115}
116
117static inline void snd_seq_inc_time_nsec(snd_seq_real_time_t *tm, unsigned long nsec)
118{
119 tm->tv_nsec += nsec;
120 snd_seq_sanity_real_time(tm);
121}
122
123/* called by timer isr */
124int snd_seq_timer_open(queue_t *q);
125int snd_seq_timer_close(queue_t *q);
126int snd_seq_timer_midi_open(queue_t *q);
127int snd_seq_timer_midi_close(queue_t *q);
128void snd_seq_timer_defaults(seq_timer_t *tmr);
129void snd_seq_timer_reset(seq_timer_t *tmr);
130int snd_seq_timer_stop(seq_timer_t *tmr);
131int snd_seq_timer_start(seq_timer_t *tmr);
132int snd_seq_timer_continue(seq_timer_t *tmr);
133int snd_seq_timer_set_tempo(seq_timer_t *tmr, int tempo);
134int snd_seq_timer_set_ppq(seq_timer_t *tmr, int ppq);
135int snd_seq_timer_set_position_tick(seq_timer_t *tmr, snd_seq_tick_time_t position);
136int snd_seq_timer_set_position_time(seq_timer_t *tmr, snd_seq_real_time_t position);
137int snd_seq_timer_set_skew(seq_timer_t *tmr, unsigned int skew, unsigned int base);
138snd_seq_real_time_t snd_seq_timer_get_cur_time(seq_timer_t *tmr);
139snd_seq_tick_time_t snd_seq_timer_get_cur_tick(seq_timer_t *tmr);
140
141#endif
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
new file mode 100644
index 000000000000..6b4e630ace54
--- /dev/null
+++ b/sound/core/seq/seq_virmidi.c
@@ -0,0 +1,551 @@
1/*
2 * Virtual Raw MIDI client on Sequencer
3 *
4 * Copyright (c) 2000 by Takashi Iwai <tiwai@suse.de>,
5 * Jaroslav Kysela <perex@perex.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23/*
24 * Virtual Raw MIDI client
25 *
26 * The virtual rawmidi client is a sequencer client which associate
27 * a rawmidi device file. The created rawmidi device file can be
28 * accessed as a normal raw midi, but its MIDI source and destination
29 * are arbitrary. For example, a user-client software synth connected
30 * to this port can be used as a normal midi device as well.
31 *
32 * The virtual rawmidi device accepts also multiple opens. Each file
33 * has its own input buffer, so that no conflict would occur. The drain
34 * of input/output buffer acts only to the local buffer.
35 *
36 */
37
38#include <sound/driver.h>
39#include <linux/init.h>
40#include <linux/wait.h>
41#include <linux/sched.h>
42#include <linux/slab.h>
43#include <sound/core.h>
44#include <sound/rawmidi.h>
45#include <sound/info.h>
46#include <sound/control.h>
47#include <sound/minors.h>
48#include <sound/seq_kernel.h>
49#include <sound/seq_midi_event.h>
50#include <sound/seq_virmidi.h>
51
52MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
53MODULE_DESCRIPTION("Virtual Raw MIDI client on Sequencer");
54MODULE_LICENSE("GPL");
55
56/*
57 * initialize an event record
58 */
59static void snd_virmidi_init_event(snd_virmidi_t *vmidi, snd_seq_event_t *ev)
60{
61 memset(ev, 0, sizeof(*ev));
62 ev->source.port = vmidi->port;
63 switch (vmidi->seq_mode) {
64 case SNDRV_VIRMIDI_SEQ_DISPATCH:
65 ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
66 break;
67 case SNDRV_VIRMIDI_SEQ_ATTACH:
68 /* FIXME: source and destination are same - not good.. */
69 ev->dest.client = vmidi->client;
70 ev->dest.port = vmidi->port;
71 break;
72 }
73 ev->type = SNDRV_SEQ_EVENT_NONE;
74}
75
76/*
77 * decode input event and put to read buffer of each opened file
78 */
79static int snd_virmidi_dev_receive_event(snd_virmidi_dev_t *rdev, snd_seq_event_t *ev)
80{
81 snd_virmidi_t *vmidi;
82 struct list_head *list;
83 unsigned char msg[4];
84 int len;
85
86 read_lock(&rdev->filelist_lock);
87 list_for_each(list, &rdev->filelist) {
88 vmidi = list_entry(list, snd_virmidi_t, list);
89 if (!vmidi->trigger)
90 continue;
91 if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
92 if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
93 continue;
94 snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)snd_rawmidi_receive, vmidi->substream);
95 } else {
96 len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
97 if (len > 0)
98 snd_rawmidi_receive(vmidi->substream, msg, len);
99 }
100 }
101 read_unlock(&rdev->filelist_lock);
102
103 return 0;
104}
105
106/*
107 * receive an event from the remote virmidi port
108 *
109 * for rawmidi inputs, you can call this function from the event
110 * handler of a remote port which is attached to the virmidi via
111 * SNDRV_VIRMIDI_SEQ_ATTACH.
112 */
113/* exported */
114int snd_virmidi_receive(snd_rawmidi_t *rmidi, snd_seq_event_t *ev)
115{
116 snd_virmidi_dev_t *rdev;
117
118 rdev = rmidi->private_data;
119 return snd_virmidi_dev_receive_event(rdev, ev);
120}
121
122/*
123 * event handler of virmidi port
124 */
125static int snd_virmidi_event_input(snd_seq_event_t *ev, int direct,
126 void *private_data, int atomic, int hop)
127{
128 snd_virmidi_dev_t *rdev;
129
130 rdev = private_data;
131 if (!(rdev->flags & SNDRV_VIRMIDI_USE))
132 return 0; /* ignored */
133 return snd_virmidi_dev_receive_event(rdev, ev);
134}
135
136/*
137 * trigger rawmidi stream for input
138 */
139static void snd_virmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
140{
141 snd_virmidi_t *vmidi = substream->runtime->private_data;
142
143 if (up) {
144 vmidi->trigger = 1;
145 } else {
146 vmidi->trigger = 0;
147 }
148}
149
150/*
151 * trigger rawmidi stream for output
152 */
153static void snd_virmidi_output_trigger(snd_rawmidi_substream_t * substream, int up)
154{
155 snd_virmidi_t *vmidi = substream->runtime->private_data;
156 int count, res;
157 unsigned char buf[32], *pbuf;
158
159 if (up) {
160 vmidi->trigger = 1;
161 if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
162 !(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
163 snd_rawmidi_transmit_ack(substream, substream->runtime->buffer_size - substream->runtime->avail);
164 return; /* ignored */
165 }
166 if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
167 if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, 0, 0) < 0)
168 return;
169 vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
170 }
171 while (1) {
172 count = snd_rawmidi_transmit_peek(substream, buf, sizeof(buf));
173 if (count <= 0)
174 break;
175 pbuf = buf;
176 while (count > 0) {
177 res = snd_midi_event_encode(vmidi->parser, pbuf, count, &vmidi->event);
178 if (res < 0) {
179 snd_midi_event_reset_encode(vmidi->parser);
180 continue;
181 }
182 snd_rawmidi_transmit_ack(substream, res);
183 pbuf += res;
184 count -= res;
185 if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
186 if (snd_seq_kernel_client_dispatch(vmidi->client, &vmidi->event, 0, 0) < 0)
187 return;
188 vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
189 }
190 }
191 }
192 } else {
193 vmidi->trigger = 0;
194 }
195}
196
197/*
198 * open rawmidi handle for input
199 */
200static int snd_virmidi_input_open(snd_rawmidi_substream_t * substream)
201{
202 snd_virmidi_dev_t *rdev = substream->rmidi->private_data;
203 snd_rawmidi_runtime_t *runtime = substream->runtime;
204 snd_virmidi_t *vmidi;
205 unsigned long flags;
206
207 vmidi = kcalloc(1, sizeof(*vmidi), GFP_KERNEL);
208 if (vmidi == NULL)
209 return -ENOMEM;
210 vmidi->substream = substream;
211 if (snd_midi_event_new(0, &vmidi->parser) < 0) {
212 kfree(vmidi);
213 return -ENOMEM;
214 }
215 vmidi->seq_mode = rdev->seq_mode;
216 vmidi->client = rdev->client;
217 vmidi->port = rdev->port;
218 runtime->private_data = vmidi;
219 write_lock_irqsave(&rdev->filelist_lock, flags);
220 list_add_tail(&vmidi->list, &rdev->filelist);
221 write_unlock_irqrestore(&rdev->filelist_lock, flags);
222 vmidi->rdev = rdev;
223 return 0;
224}
225
226/*
227 * open rawmidi handle for output
228 */
229static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream)
230{
231 snd_virmidi_dev_t *rdev = substream->rmidi->private_data;
232 snd_rawmidi_runtime_t *runtime = substream->runtime;
233 snd_virmidi_t *vmidi;
234
235 vmidi = kcalloc(1, sizeof(*vmidi), GFP_KERNEL);
236 if (vmidi == NULL)
237 return -ENOMEM;
238 vmidi->substream = substream;
239 if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &vmidi->parser) < 0) {
240 kfree(vmidi);
241 return -ENOMEM;
242 }
243 vmidi->seq_mode = rdev->seq_mode;
244 vmidi->client = rdev->client;
245 vmidi->port = rdev->port;
246 snd_virmidi_init_event(vmidi, &vmidi->event);
247 vmidi->rdev = rdev;
248 runtime->private_data = vmidi;
249 return 0;
250}
251
252/*
253 * close rawmidi handle for input
254 */
255static int snd_virmidi_input_close(snd_rawmidi_substream_t * substream)
256{
257 snd_virmidi_t *vmidi = substream->runtime->private_data;
258 snd_midi_event_free(vmidi->parser);
259 list_del(&vmidi->list);
260 substream->runtime->private_data = NULL;
261 kfree(vmidi);
262 return 0;
263}
264
265/*
266 * close rawmidi handle for output
267 */
268static int snd_virmidi_output_close(snd_rawmidi_substream_t * substream)
269{
270 snd_virmidi_t *vmidi = substream->runtime->private_data;
271 snd_midi_event_free(vmidi->parser);
272 substream->runtime->private_data = NULL;
273 kfree(vmidi);
274 return 0;
275}
276
277/*
278 * subscribe callback - allow output to rawmidi device
279 */
280static int snd_virmidi_subscribe(void *private_data, snd_seq_port_subscribe_t *info)
281{
282 snd_virmidi_dev_t *rdev;
283
284 rdev = private_data;
285 if (!try_module_get(rdev->card->module))
286 return -EFAULT;
287 rdev->flags |= SNDRV_VIRMIDI_SUBSCRIBE;
288 return 0;
289}
290
291/*
292 * unsubscribe callback - disallow output to rawmidi device
293 */
294static int snd_virmidi_unsubscribe(void *private_data, snd_seq_port_subscribe_t *info)
295{
296 snd_virmidi_dev_t *rdev;
297
298 rdev = private_data;
299 rdev->flags &= ~SNDRV_VIRMIDI_SUBSCRIBE;
300 module_put(rdev->card->module);
301 return 0;
302}
303
304
305/*
306 * use callback - allow input to rawmidi device
307 */
308static int snd_virmidi_use(void *private_data, snd_seq_port_subscribe_t *info)
309{
310 snd_virmidi_dev_t *rdev;
311
312 rdev = private_data;
313 if (!try_module_get(rdev->card->module))
314 return -EFAULT;
315 rdev->flags |= SNDRV_VIRMIDI_USE;
316 return 0;
317}
318
319/*
320 * unuse callback - disallow input to rawmidi device
321 */
322static int snd_virmidi_unuse(void *private_data, snd_seq_port_subscribe_t *info)
323{
324 snd_virmidi_dev_t *rdev;
325
326 rdev = private_data;
327 rdev->flags &= ~SNDRV_VIRMIDI_USE;
328 module_put(rdev->card->module);
329 return 0;
330}
331
332
333/*
334 * Register functions
335 */
336
337static snd_rawmidi_ops_t snd_virmidi_input_ops = {
338 .open = snd_virmidi_input_open,
339 .close = snd_virmidi_input_close,
340 .trigger = snd_virmidi_input_trigger,
341};
342
343static snd_rawmidi_ops_t snd_virmidi_output_ops = {
344 .open = snd_virmidi_output_open,
345 .close = snd_virmidi_output_close,
346 .trigger = snd_virmidi_output_trigger,
347};
348
349/*
350 * create a sequencer client and a port
351 */
352static int snd_virmidi_dev_attach_seq(snd_virmidi_dev_t *rdev)
353{
354 int client;
355 snd_seq_client_callback_t callbacks;
356 snd_seq_port_callback_t pcallbacks;
357 snd_seq_client_info_t *info;
358 snd_seq_port_info_t *pinfo;
359 int err;
360
361 if (rdev->client >= 0)
362 return 0;
363
364 info = kmalloc(sizeof(*info), GFP_KERNEL);
365 pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
366 if (! info || ! pinfo) {
367 err = -ENOMEM;
368 goto __error;
369 }
370
371 memset(&callbacks, 0, sizeof(callbacks));
372 callbacks.private_data = rdev;
373 callbacks.allow_input = 1;
374 callbacks.allow_output = 1;
375 client = snd_seq_create_kernel_client(rdev->card, rdev->device, &callbacks);
376 if (client < 0) {
377 err = client;
378 goto __error;
379 }
380 rdev->client = client;
381
382 /* set client name */
383 memset(info, 0, sizeof(*info));
384 info->client = client;
385 info->type = KERNEL_CLIENT;
386 sprintf(info->name, "%s %d-%d", rdev->rmidi->name, rdev->card->number, rdev->device);
387 snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &info);
388
389 /* create a port */
390 memset(pinfo, 0, sizeof(*pinfo));
391 pinfo->addr.client = client;
392 sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
393 /* set all capabilities */
394 pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
395 pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
396 pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
397 pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC;
398 pinfo->midi_channels = 16;
399 memset(&pcallbacks, 0, sizeof(pcallbacks));
400 pcallbacks.owner = THIS_MODULE;
401 pcallbacks.private_data = rdev;
402 pcallbacks.subscribe = snd_virmidi_subscribe;
403 pcallbacks.unsubscribe = snd_virmidi_unsubscribe;
404 pcallbacks.use = snd_virmidi_use;
405 pcallbacks.unuse = snd_virmidi_unuse;
406 pcallbacks.event_input = snd_virmidi_event_input;
407 pinfo->kernel = &pcallbacks;
408 err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, &pinfo);
409 if (err < 0) {
410 snd_seq_delete_kernel_client(client);
411 rdev->client = -1;
412 goto __error;
413 }
414
415 rdev->port = pinfo->addr.port;
416 err = 0; /* success */
417
418 __error:
419 kfree(info);
420 kfree(pinfo);
421 return err;
422}
423
424
425/*
426 * release the sequencer client
427 */
428static void snd_virmidi_dev_detach_seq(snd_virmidi_dev_t *rdev)
429{
430 if (rdev->client >= 0) {
431 snd_seq_delete_kernel_client(rdev->client);
432 rdev->client = -1;
433 }
434}
435
436/*
437 * register the device
438 */
439static int snd_virmidi_dev_register(snd_rawmidi_t *rmidi)
440{
441 snd_virmidi_dev_t *rdev = rmidi->private_data;
442 int err;
443
444 switch (rdev->seq_mode) {
445 case SNDRV_VIRMIDI_SEQ_DISPATCH:
446 err = snd_virmidi_dev_attach_seq(rdev);
447 if (err < 0)
448 return err;
449 break;
450 case SNDRV_VIRMIDI_SEQ_ATTACH:
451 if (rdev->client == 0)
452 return -EINVAL;
453 /* should check presence of port more strictly.. */
454 break;
455 default:
456 snd_printk(KERN_ERR "seq_mode is not set: %d\n", rdev->seq_mode);
457 return -EINVAL;
458 }
459 return 0;
460}
461
462
463/*
464 * unregister the device
465 */
466static int snd_virmidi_dev_unregister(snd_rawmidi_t *rmidi)
467{
468 snd_virmidi_dev_t *rdev = rmidi->private_data;
469
470 if (rdev->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH)
471 snd_virmidi_dev_detach_seq(rdev);
472 return 0;
473}
474
475/*
476 *
477 */
478static snd_rawmidi_global_ops_t snd_virmidi_global_ops = {
479 .dev_register = snd_virmidi_dev_register,
480 .dev_unregister = snd_virmidi_dev_unregister,
481};
482
483/*
484 * free device
485 */
486static void snd_virmidi_free(snd_rawmidi_t *rmidi)
487{
488 snd_virmidi_dev_t *rdev = rmidi->private_data;
489 kfree(rdev);
490}
491
492/*
493 * create a new device
494 *
495 */
496/* exported */
497int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi)
498{
499 snd_rawmidi_t *rmidi;
500 snd_virmidi_dev_t *rdev;
501 int err;
502
503 *rrmidi = NULL;
504 if ((err = snd_rawmidi_new(card, "VirMidi", device,
505 16, /* may be configurable */
506 16, /* may be configurable */
507 &rmidi)) < 0)
508 return err;
509 strcpy(rmidi->name, rmidi->id);
510 rdev = kcalloc(1, sizeof(*rdev), GFP_KERNEL);
511 if (rdev == NULL) {
512 snd_device_free(card, rmidi);
513 return -ENOMEM;
514 }
515 rdev->card = card;
516 rdev->rmidi = rmidi;
517 rdev->device = device;
518 rdev->client = -1;
519 rwlock_init(&rdev->filelist_lock);
520 INIT_LIST_HEAD(&rdev->filelist);
521 rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
522 rmidi->private_data = rdev;
523 rmidi->private_free = snd_virmidi_free;
524 rmidi->ops = &snd_virmidi_global_ops;
525 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_virmidi_input_ops);
526 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_virmidi_output_ops);
527 rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT |
528 SNDRV_RAWMIDI_INFO_OUTPUT |
529 SNDRV_RAWMIDI_INFO_DUPLEX;
530 *rrmidi = rmidi;
531 return 0;
532}
533
534/*
535 * ENTRY functions
536 */
537
538static int __init alsa_virmidi_init(void)
539{
540 return 0;
541}
542
543static void __exit alsa_virmidi_exit(void)
544{
545}
546
547module_init(alsa_virmidi_init)
548module_exit(alsa_virmidi_exit)
549
550EXPORT_SYMBOL(snd_virmidi_new);
551EXPORT_SYMBOL(snd_virmidi_receive);
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
new file mode 100644
index 000000000000..74745da9deb6
--- /dev/null
+++ b/sound/core/sgbuf.c
@@ -0,0 +1,111 @@
1/*
2 * Scatter-Gather buffer
3 *
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
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/config.h>
23#include <linux/slab.h>
24#include <linux/mm.h>
25#include <linux/vmalloc.h>
26#include <sound/memalloc.h>
27
28
29/* table entries are align to 32 */
30#define SGBUF_TBL_ALIGN 32
31#define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN)
32
33int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
34{
35 struct snd_sg_buf *sgbuf = dmab->private_data;
36 struct snd_dma_buffer tmpb;
37 int i;
38
39 if (! sgbuf)
40 return -EINVAL;
41
42 tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
43 tmpb.dev.dev = sgbuf->dev;
44 for (i = 0; i < sgbuf->pages; i++) {
45 tmpb.area = sgbuf->table[i].buf;
46 tmpb.addr = sgbuf->table[i].addr;
47 tmpb.bytes = PAGE_SIZE;
48 snd_dma_free_pages(&tmpb);
49 }
50 if (dmab->area)
51 vunmap(dmab->area);
52 dmab->area = NULL;
53
54 kfree(sgbuf->table);
55 kfree(sgbuf->page_table);
56 kfree(sgbuf);
57 dmab->private_data = NULL;
58
59 return 0;
60}
61
62void *snd_malloc_sgbuf_pages(struct device *device,
63 size_t size, struct snd_dma_buffer *dmab,
64 size_t *res_size)
65{
66 struct snd_sg_buf *sgbuf;
67 unsigned int i, pages;
68 struct snd_dma_buffer tmpb;
69
70 dmab->area = NULL;
71 dmab->addr = 0;
72 dmab->private_data = sgbuf = kmalloc(sizeof(*sgbuf), GFP_KERNEL);
73 if (! sgbuf)
74 return NULL;
75 memset(sgbuf, 0, sizeof(*sgbuf));
76 sgbuf->dev = device;
77 pages = snd_sgbuf_aligned_pages(size);
78 sgbuf->tblsize = sgbuf_align_table(pages);
79 sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL);
80 if (! sgbuf->table)
81 goto _failed;
82 memset(sgbuf->table, 0, sizeof(*sgbuf->table) * sgbuf->tblsize);
83 sgbuf->page_table = kmalloc(sizeof(*sgbuf->page_table) * sgbuf->tblsize, GFP_KERNEL);
84 if (! sgbuf->page_table)
85 goto _failed;
86 memset(sgbuf->page_table, 0, sizeof(*sgbuf->page_table) * sgbuf->tblsize);
87
88 /* allocate each page */
89 for (i = 0; i < pages; i++) {
90 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, device, PAGE_SIZE, &tmpb) < 0) {
91 if (res_size == NULL)
92 goto _failed;
93 *res_size = size = sgbuf->pages * PAGE_SIZE;
94 break;
95 }
96 sgbuf->table[i].buf = tmpb.area;
97 sgbuf->table[i].addr = tmpb.addr;
98 sgbuf->page_table[i] = virt_to_page(tmpb.area);
99 sgbuf->pages++;
100 }
101
102 sgbuf->size = size;
103 dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, PAGE_KERNEL);
104 if (! dmab->area)
105 goto _failed;
106 return dmab->area;
107
108 _failed:
109 snd_free_sgbuf_pages(dmab); /* free the table */
110 return NULL;
111}
diff --git a/sound/core/sound.c b/sound/core/sound.c
new file mode 100644
index 000000000000..88e052079f85
--- /dev/null
+++ b/sound/core/sound.c
@@ -0,0 +1,491 @@
1/*
2 * Advanced Linux Sound Architecture
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/moduleparam.h>
27#include <sound/core.h>
28#include <sound/minors.h>
29#include <sound/info.h>
30#include <sound/version.h>
31#include <sound/control.h>
32#include <sound/initval.h>
33#include <linux/kmod.h>
34#include <linux/devfs_fs_kernel.h>
35#include <linux/device.h>
36
37#define SNDRV_OS_MINORS 256
38
39static int major = CONFIG_SND_MAJOR;
40int snd_major;
41static int cards_limit = 1;
42static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO;
43
44MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
45MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
46MODULE_LICENSE("GPL");
47module_param(major, int, 0444);
48MODULE_PARM_DESC(major, "Major # for sound driver.");
49module_param(cards_limit, int, 0444);
50MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
51#ifdef CONFIG_DEVFS_FS
52module_param(device_mode, int, 0444);
53MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs.");
54#endif
55MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
56
57/* this one holds the actual max. card number currently available.
58 * as default, it's identical with cards_limit option. when more
59 * modules are loaded manually, this limit number increases, too.
60 */
61int snd_ecards_limit;
62
63static struct list_head snd_minors_hash[SNDRV_CARDS];
64
65static DECLARE_MUTEX(sound_mutex);
66
67extern struct class_simple *sound_class;
68
69
70#ifdef CONFIG_KMOD
71
72/**
73 * snd_request_card - try to load the card module
74 * @card: the card number
75 *
76 * Tries to load the module "snd-card-X" for the given card number
77 * via KMOD. Returns immediately if already loaded.
78 */
79void snd_request_card(int card)
80{
81 int locked;
82
83 if (! current->fs->root)
84 return;
85 read_lock(&snd_card_rwlock);
86 locked = snd_cards_lock & (1 << card);
87 read_unlock(&snd_card_rwlock);
88 if (locked)
89 return;
90 if (card < 0 || card >= cards_limit)
91 return;
92 request_module("snd-card-%i", card);
93}
94
95static void snd_request_other(int minor)
96{
97 char *str;
98
99 if (! current->fs->root)
100 return;
101 switch (minor) {
102 case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break;
103 case SNDRV_MINOR_TIMER: str = "snd-timer"; break;
104 default: return;
105 }
106 request_module(str);
107}
108
109#endif /* request_module support */
110
111static snd_minor_t *snd_minor_search(int minor)
112{
113 struct list_head *list;
114 snd_minor_t *mptr;
115
116 list_for_each(list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]) {
117 mptr = list_entry(list, snd_minor_t, list);
118 if (mptr->number == minor)
119 return mptr;
120 }
121 return NULL;
122}
123
124static int snd_open(struct inode *inode, struct file *file)
125{
126 int minor = iminor(inode);
127 int card = SNDRV_MINOR_CARD(minor);
128 int dev = SNDRV_MINOR_DEVICE(minor);
129 snd_minor_t *mptr = NULL;
130 struct file_operations *old_fops;
131 int err = 0;
132
133 if (dev != SNDRV_MINOR_SEQUENCER && dev != SNDRV_MINOR_TIMER) {
134 if (snd_cards[card] == NULL) {
135#ifdef CONFIG_KMOD
136 snd_request_card(card);
137 if (snd_cards[card] == NULL)
138#endif
139 return -ENODEV;
140 }
141 } else {
142#ifdef CONFIG_KMOD
143 if ((mptr = snd_minor_search(minor)) == NULL)
144 snd_request_other(minor);
145#endif
146 }
147 if (mptr == NULL && (mptr = snd_minor_search(minor)) == NULL)
148 return -ENODEV;
149 old_fops = file->f_op;
150 file->f_op = fops_get(mptr->f_ops);
151 if (file->f_op->open)
152 err = file->f_op->open(inode, file);
153 if (err) {
154 fops_put(file->f_op);
155 file->f_op = fops_get(old_fops);
156 }
157 fops_put(old_fops);
158 return err;
159}
160
161static struct file_operations snd_fops =
162{
163 .owner = THIS_MODULE,
164 .open = snd_open
165};
166
167static int snd_kernel_minor(int type, snd_card_t * card, int dev)
168{
169 int minor;
170
171 switch (type) {
172 case SNDRV_DEVICE_TYPE_SEQUENCER:
173 case SNDRV_DEVICE_TYPE_TIMER:
174 minor = type;
175 break;
176 case SNDRV_DEVICE_TYPE_CONTROL:
177 snd_assert(card != NULL, return -EINVAL);
178 minor = SNDRV_MINOR(card->number, type);
179 break;
180 case SNDRV_DEVICE_TYPE_HWDEP:
181 case SNDRV_DEVICE_TYPE_RAWMIDI:
182 case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
183 case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
184 snd_assert(card != NULL, return -EINVAL);
185 minor = SNDRV_MINOR(card->number, type + dev);
186 break;
187 default:
188 return -EINVAL;
189 }
190 snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
191 return minor;
192}
193
194/**
195 * snd_register_device - Register the ALSA device file for the card
196 * @type: the device type, SNDRV_DEVICE_TYPE_XXX
197 * @card: the card instance
198 * @dev: the device index
199 * @reg: the snd_minor_t record
200 * @name: the device file name
201 *
202 * Registers an ALSA device file for the given card.
203 * The operators have to be set in reg parameter.
204 *
205 * Retrurns zero if successful, or a negative error code on failure.
206 */
207int snd_register_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, const char *name)
208{
209 int minor = snd_kernel_minor(type, card, dev);
210 snd_minor_t *preg;
211 struct device *device = NULL;
212
213 if (minor < 0)
214 return minor;
215 snd_assert(name, return -EINVAL);
216 preg = (snd_minor_t *)kmalloc(sizeof(snd_minor_t) + strlen(name) + 1, GFP_KERNEL);
217 if (preg == NULL)
218 return -ENOMEM;
219 *preg = *reg;
220 preg->number = minor;
221 preg->device = dev;
222 strcpy(preg->name, name);
223 down(&sound_mutex);
224 if (snd_minor_search(minor)) {
225 up(&sound_mutex);
226 kfree(preg);
227 return -EBUSY;
228 }
229 list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]);
230 if (strncmp(name, "controlC", 8) || card->number >= cards_limit)
231 devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name);
232 if (card)
233 device = card->dev;
234 class_simple_device_add(sound_class, MKDEV(major, minor), device, name);
235
236 up(&sound_mutex);
237 return 0;
238}
239
240/**
241 * snd_unregister_device - unregister the device on the given card
242 * @type: the device type, SNDRV_DEVICE_TYPE_XXX
243 * @card: the card instance
244 * @dev: the device index
245 *
246 * Unregisters the device file already registered via
247 * snd_register_device().
248 *
249 * Returns zero if sucecessful, or a negative error code on failure
250 */
251int snd_unregister_device(int type, snd_card_t * card, int dev)
252{
253 int minor = snd_kernel_minor(type, card, dev);
254 snd_minor_t *mptr;
255
256 if (minor < 0)
257 return minor;
258 down(&sound_mutex);
259 if ((mptr = snd_minor_search(minor)) == NULL) {
260 up(&sound_mutex);
261 return -EINVAL;
262 }
263
264 if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) /* created in sound.c */
265 devfs_remove("snd/%s", mptr->name);
266 class_simple_device_remove(MKDEV(major, minor));
267
268 list_del(&mptr->list);
269 up(&sound_mutex);
270 kfree(mptr);
271 return 0;
272}
273
274/*
275 * INFO PART
276 */
277
278static snd_info_entry_t *snd_minor_info_entry = NULL;
279
280static void snd_minor_info_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
281{
282 int card, device;
283 struct list_head *list;
284 snd_minor_t *mptr;
285
286 down(&sound_mutex);
287 for (card = 0; card < SNDRV_CARDS; card++) {
288 list_for_each(list, &snd_minors_hash[card]) {
289 mptr = list_entry(list, snd_minor_t, list);
290 if (SNDRV_MINOR_DEVICE(mptr->number) != SNDRV_MINOR_SEQUENCER) {
291 if ((device = mptr->device) >= 0)
292 snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", mptr->number, card, device, mptr->comment);
293 else
294 snd_iprintf(buffer, "%3i: [%i] : %s\n", mptr->number, card, mptr->comment);
295 } else {
296 snd_iprintf(buffer, "%3i: : %s\n", mptr->number, mptr->comment);
297 }
298 }
299 }
300 up(&sound_mutex);
301}
302
303int __init snd_minor_info_init(void)
304{
305 snd_info_entry_t *entry;
306
307 entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
308 if (entry) {
309 entry->c.text.read_size = PAGE_SIZE;
310 entry->c.text.read = snd_minor_info_read;
311 if (snd_info_register(entry) < 0) {
312 snd_info_free_entry(entry);
313 entry = NULL;
314 }
315 }
316 snd_minor_info_entry = entry;
317 return 0;
318}
319
320int __exit snd_minor_info_done(void)
321{
322 if (snd_minor_info_entry)
323 snd_info_unregister(snd_minor_info_entry);
324 return 0;
325}
326
327/*
328 * INIT PART
329 */
330
331static int __init alsa_sound_init(void)
332{
333 short controlnum;
334 int err;
335 int card;
336
337 snd_major = major;
338 snd_ecards_limit = cards_limit;
339 for (card = 0; card < SNDRV_CARDS; card++)
340 INIT_LIST_HEAD(&snd_minors_hash[card]);
341 if ((err = snd_oss_init_module()) < 0)
342 return err;
343 devfs_mk_dir("snd");
344 if (register_chrdev(major, "alsa", &snd_fops)) {
345 snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
346 devfs_remove("snd");
347 return -EIO;
348 }
349 snd_memory_init();
350 if (snd_info_init() < 0) {
351 snd_memory_done();
352 unregister_chrdev(major, "alsa");
353 devfs_remove("snd");
354 return -ENOMEM;
355 }
356 snd_info_minor_register();
357 for (controlnum = 0; controlnum < cards_limit; controlnum++)
358 devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum);
359#ifndef MODULE
360 printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
361#endif
362 return 0;
363}
364
365static void __exit alsa_sound_exit(void)
366{
367 short controlnum;
368
369 for (controlnum = 0; controlnum < cards_limit; controlnum++)
370 devfs_remove("snd/controlC%d", controlnum);
371
372 snd_info_minor_unregister();
373 snd_info_done();
374 snd_memory_done();
375 if (unregister_chrdev(major, "alsa") != 0)
376 snd_printk(KERN_ERR "unable to unregister major device number %d\n", major);
377 devfs_remove("snd");
378}
379
380module_init(alsa_sound_init)
381module_exit(alsa_sound_exit)
382
383 /* sound.c */
384EXPORT_SYMBOL(snd_major);
385EXPORT_SYMBOL(snd_ecards_limit);
386#if defined(CONFIG_KMOD)
387EXPORT_SYMBOL(snd_request_card);
388#endif
389EXPORT_SYMBOL(snd_register_device);
390EXPORT_SYMBOL(snd_unregister_device);
391#if defined(CONFIG_SND_OSSEMUL)
392EXPORT_SYMBOL(snd_register_oss_device);
393EXPORT_SYMBOL(snd_unregister_oss_device);
394#endif
395 /* memory.c */
396#ifdef CONFIG_SND_DEBUG_MEMORY
397EXPORT_SYMBOL(snd_hidden_kmalloc);
398EXPORT_SYMBOL(snd_hidden_kcalloc);
399EXPORT_SYMBOL(snd_hidden_kfree);
400EXPORT_SYMBOL(snd_hidden_vmalloc);
401EXPORT_SYMBOL(snd_hidden_vfree);
402#endif
403EXPORT_SYMBOL(snd_kmalloc_strdup);
404EXPORT_SYMBOL(copy_to_user_fromio);
405EXPORT_SYMBOL(copy_from_user_toio);
406 /* init.c */
407EXPORT_SYMBOL(snd_cards);
408#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
409EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
410#endif
411EXPORT_SYMBOL(snd_card_new);
412EXPORT_SYMBOL(snd_card_disconnect);
413EXPORT_SYMBOL(snd_card_free);
414EXPORT_SYMBOL(snd_card_free_in_thread);
415EXPORT_SYMBOL(snd_card_register);
416EXPORT_SYMBOL(snd_component_add);
417EXPORT_SYMBOL(snd_card_file_add);
418EXPORT_SYMBOL(snd_card_file_remove);
419#ifdef CONFIG_PM
420EXPORT_SYMBOL(snd_power_wait);
421EXPORT_SYMBOL(snd_card_set_pm_callback);
422#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM)
423EXPORT_SYMBOL(snd_card_set_generic_pm_callback);
424#endif
425#ifdef CONFIG_PCI
426EXPORT_SYMBOL(snd_card_pci_suspend);
427EXPORT_SYMBOL(snd_card_pci_resume);
428#endif
429#endif
430 /* device.c */
431EXPORT_SYMBOL(snd_device_new);
432EXPORT_SYMBOL(snd_device_register);
433EXPORT_SYMBOL(snd_device_free);
434EXPORT_SYMBOL(snd_device_free_all);
435 /* isadma.c */
436#ifdef CONFIG_ISA
437EXPORT_SYMBOL(snd_dma_program);
438EXPORT_SYMBOL(snd_dma_disable);
439EXPORT_SYMBOL(snd_dma_pointer);
440#endif
441 /* info.c */
442#ifdef CONFIG_PROC_FS
443EXPORT_SYMBOL(snd_seq_root);
444EXPORT_SYMBOL(snd_iprintf);
445EXPORT_SYMBOL(snd_info_get_line);
446EXPORT_SYMBOL(snd_info_get_str);
447EXPORT_SYMBOL(snd_info_create_module_entry);
448EXPORT_SYMBOL(snd_info_create_card_entry);
449EXPORT_SYMBOL(snd_info_free_entry);
450EXPORT_SYMBOL(snd_info_register);
451EXPORT_SYMBOL(snd_info_unregister);
452EXPORT_SYMBOL(snd_card_proc_new);
453#endif
454 /* info_oss.c */
455#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
456EXPORT_SYMBOL(snd_oss_info_register);
457#endif
458 /* control.c */
459EXPORT_SYMBOL(snd_ctl_new);
460EXPORT_SYMBOL(snd_ctl_new1);
461EXPORT_SYMBOL(snd_ctl_free_one);
462EXPORT_SYMBOL(snd_ctl_add);
463EXPORT_SYMBOL(snd_ctl_remove);
464EXPORT_SYMBOL(snd_ctl_remove_id);
465EXPORT_SYMBOL(snd_ctl_rename_id);
466EXPORT_SYMBOL(snd_ctl_find_numid);
467EXPORT_SYMBOL(snd_ctl_find_id);
468EXPORT_SYMBOL(snd_ctl_notify);
469EXPORT_SYMBOL(snd_ctl_register_ioctl);
470EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
471#ifdef CONFIG_COMPAT
472EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
473EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
474#endif
475EXPORT_SYMBOL(snd_ctl_elem_read);
476EXPORT_SYMBOL(snd_ctl_elem_write);
477 /* misc.c */
478EXPORT_SYMBOL(snd_task_name);
479#ifdef CONFIG_SND_VERBOSE_PRINTK
480EXPORT_SYMBOL(snd_verbose_printk);
481#endif
482#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK)
483EXPORT_SYMBOL(snd_verbose_printd);
484#endif
485 /* wrappers */
486#ifdef CONFIG_SND_DEBUG_MEMORY
487EXPORT_SYMBOL(snd_wrapper_kmalloc);
488EXPORT_SYMBOL(snd_wrapper_kfree);
489EXPORT_SYMBOL(snd_wrapper_vmalloc);
490EXPORT_SYMBOL(snd_wrapper_vfree);
491#endif
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
new file mode 100644
index 000000000000..de39d212bc15
--- /dev/null
+++ b/sound/core/sound_oss.c
@@ -0,0 +1,250 @@
1/*
2 * Advanced Linux Sound Architecture
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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
24#ifdef CONFIG_SND_OSSEMUL
25
26#if !defined(CONFIG_SOUND) && !(defined(MODULE) && defined(CONFIG_SOUND_MODULE))
27#error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
28#endif
29
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/time.h>
33#include <sound/core.h>
34#include <sound/minors.h>
35#include <sound/info.h>
36#include <linux/sound.h>
37
38#define SNDRV_OS_MINORS 256
39
40static struct list_head snd_oss_minors_hash[SNDRV_CARDS];
41
42static DECLARE_MUTEX(sound_oss_mutex);
43
44static snd_minor_t *snd_oss_minor_search(int minor)
45{
46 struct list_head *list;
47 snd_minor_t *mptr;
48
49 list_for_each(list, &snd_oss_minors_hash[SNDRV_MINOR_OSS_CARD(minor)]) {
50 mptr = list_entry(list, snd_minor_t, list);
51 if (mptr->number == minor)
52 return mptr;
53 }
54 return NULL;
55}
56
57static int snd_oss_kernel_minor(int type, snd_card_t * card, int dev)
58{
59 int minor;
60
61 switch (type) {
62 case SNDRV_OSS_DEVICE_TYPE_MIXER:
63 snd_assert(card != NULL && dev <= 1, return -EINVAL);
64 minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIXER1 : SNDRV_MINOR_OSS_MIXER));
65 break;
66 case SNDRV_OSS_DEVICE_TYPE_SEQUENCER:
67 minor = SNDRV_MINOR_OSS_SEQUENCER;
68 break;
69 case SNDRV_OSS_DEVICE_TYPE_MUSIC:
70 minor = SNDRV_MINOR_OSS_MUSIC;
71 break;
72 case SNDRV_OSS_DEVICE_TYPE_PCM:
73 snd_assert(card != NULL && dev <= 1, return -EINVAL);
74 minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_PCM1 : SNDRV_MINOR_OSS_PCM));
75 break;
76 case SNDRV_OSS_DEVICE_TYPE_MIDI:
77 snd_assert(card != NULL && dev <= 1, return -EINVAL);
78 minor = SNDRV_MINOR_OSS(card->number, (dev ? SNDRV_MINOR_OSS_MIDI1 : SNDRV_MINOR_OSS_MIDI));
79 break;
80 case SNDRV_OSS_DEVICE_TYPE_DMFM:
81 minor = SNDRV_MINOR_OSS(card->number, SNDRV_MINOR_OSS_DMFM);
82 break;
83 case SNDRV_OSS_DEVICE_TYPE_SNDSTAT:
84 minor = SNDRV_MINOR_OSS_SNDSTAT;
85 break;
86 default:
87 return -EINVAL;
88 }
89 snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
90 return minor;
91}
92
93int snd_register_oss_device(int type, snd_card_t * card, int dev, snd_minor_t * reg, const char *name)
94{
95 int minor = snd_oss_kernel_minor(type, card, dev);
96 int minor_unit;
97 snd_minor_t *preg;
98 int cidx = SNDRV_MINOR_OSS_CARD(minor);
99 int track2 = -1;
100 int register1 = -1, register2 = -1;
101
102 if (minor < 0)
103 return minor;
104 preg = (snd_minor_t *)kmalloc(sizeof(snd_minor_t), GFP_KERNEL);
105 if (preg == NULL)
106 return -ENOMEM;
107 *preg = *reg;
108 preg->number = minor;
109 preg->device = dev;
110 down(&sound_oss_mutex);
111 list_add_tail(&preg->list, &snd_oss_minors_hash[cidx]);
112 minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
113 switch (minor_unit) {
114 case SNDRV_MINOR_OSS_PCM:
115 track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
116 break;
117 case SNDRV_MINOR_OSS_MIDI:
118 track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI);
119 break;
120 case SNDRV_MINOR_OSS_MIDI1:
121 track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
122 break;
123 }
124 register1 = register_sound_special(reg->f_ops, minor);
125 if (register1 != minor)
126 goto __end;
127 if (track2 >= 0) {
128 register2 = register_sound_special(reg->f_ops, track2);
129 if (register2 != track2)
130 goto __end;
131 }
132 up(&sound_oss_mutex);
133 return 0;
134
135 __end:
136 if (register2 >= 0)
137 unregister_sound_special(register2);
138 if (register1 >= 0)
139 unregister_sound_special(register1);
140 list_del(&preg->list);
141 up(&sound_oss_mutex);
142 kfree(preg);
143 return -EBUSY;
144}
145
146int snd_unregister_oss_device(int type, snd_card_t * card, int dev)
147{
148 int minor = snd_oss_kernel_minor(type, card, dev);
149 int cidx = SNDRV_MINOR_OSS_CARD(minor);
150 int track2 = -1;
151 snd_minor_t *mptr;
152
153 if (minor < 0)
154 return minor;
155 down(&sound_oss_mutex);
156 mptr = snd_oss_minor_search(minor);
157 if (mptr == NULL) {
158 up(&sound_oss_mutex);
159 return -ENOENT;
160 }
161 unregister_sound_special(minor);
162 switch (SNDRV_MINOR_OSS_DEVICE(minor)) {
163 case SNDRV_MINOR_OSS_PCM:
164 track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_AUDIO);
165 break;
166 case SNDRV_MINOR_OSS_MIDI:
167 track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI);
168 break;
169 case SNDRV_MINOR_OSS_MIDI1:
170 track2 = SNDRV_MINOR_OSS(cidx, SNDRV_MINOR_OSS_DMMIDI1);
171 break;
172 }
173 if (track2 >= 0)
174 unregister_sound_special(track2);
175 list_del(&mptr->list);
176 up(&sound_oss_mutex);
177 kfree(mptr);
178 return 0;
179}
180
181/*
182 * INFO PART
183 */
184
185#ifdef CONFIG_PROC_FS
186
187static snd_info_entry_t *snd_minor_info_oss_entry = NULL;
188
189static void snd_minor_info_oss_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
190{
191 int card, dev;
192 struct list_head *list;
193 snd_minor_t *mptr;
194
195 down(&sound_oss_mutex);
196 for (card = 0; card < SNDRV_CARDS; card++) {
197 list_for_each(list, &snd_oss_minors_hash[card]) {
198 mptr = list_entry(list, snd_minor_t, list);
199 dev = SNDRV_MINOR_OSS_DEVICE(mptr->number);
200 if (dev != SNDRV_MINOR_OSS_SNDSTAT &&
201 dev != SNDRV_MINOR_OSS_SEQUENCER &&
202 dev != SNDRV_MINOR_OSS_MUSIC)
203 snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", mptr->number, card, dev, mptr->comment);
204 else
205 snd_iprintf(buffer, "%3i: : %s\n", mptr->number, mptr->comment);
206 }
207 }
208 up(&sound_oss_mutex);
209}
210
211#endif /* CONFIG_PROC_FS */
212
213int __init snd_minor_info_oss_init(void)
214{
215#ifdef CONFIG_PROC_FS
216 snd_info_entry_t *entry;
217
218 entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
219 if (entry) {
220 entry->c.text.read_size = PAGE_SIZE;
221 entry->c.text.read = snd_minor_info_oss_read;
222 if (snd_info_register(entry) < 0) {
223 snd_info_free_entry(entry);
224 entry = NULL;
225 }
226 }
227 snd_minor_info_oss_entry = entry;
228#endif
229 return 0;
230}
231
232int __exit snd_minor_info_oss_done(void)
233{
234#ifdef CONFIG_PROC_FS
235 if (snd_minor_info_oss_entry)
236 snd_info_unregister(snd_minor_info_oss_entry);
237#endif
238 return 0;
239}
240
241int __init snd_oss_init_module(void)
242{
243 int card;
244
245 for (card = 0; card < SNDRV_CARDS; card++)
246 INIT_LIST_HEAD(&snd_oss_minors_hash[card]);
247 return 0;
248}
249
250#endif /* CONFIG_SND_OSSEMUL */
diff --git a/sound/core/timer.c b/sound/core/timer.c
new file mode 100644
index 000000000000..fa762ca439be
--- /dev/null
+++ b/sound/core/timer.c
@@ -0,0 +1,1901 @@
1/*
2 * Timers abstract layer
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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/delay.h>
24#include <linux/init.h>
25#include <linux/smp_lock.h>
26#include <linux/slab.h>
27#include <linux/time.h>
28#include <linux/moduleparam.h>
29#include <sound/core.h>
30#include <sound/timer.h>
31#include <sound/control.h>
32#include <sound/info.h>
33#include <sound/minors.h>
34#include <sound/initval.h>
35#include <linux/kmod.h>
36#ifdef CONFIG_KERNELD
37#include <linux/kerneld.h>
38#endif
39
40#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
41#define DEFAULT_TIMER_LIMIT 3
42#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE)
43#define DEFAULT_TIMER_LIMIT 2
44#else
45#define DEFAULT_TIMER_LIMIT 1
46#endif
47
48static int timer_limit = DEFAULT_TIMER_LIMIT;
49MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
50MODULE_DESCRIPTION("ALSA timer interface");
51MODULE_LICENSE("GPL");
52module_param(timer_limit, int, 0444);
53MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
54
55typedef struct {
56 snd_timer_instance_t *timeri;
57 int tread; /* enhanced read with timestamps and events */
58 unsigned long ticks;
59 unsigned long overrun;
60 int qhead;
61 int qtail;
62 int qused;
63 int queue_size;
64 snd_timer_read_t *queue;
65 snd_timer_tread_t *tqueue;
66 spinlock_t qlock;
67 unsigned long last_resolution;
68 unsigned int filter;
69 struct timespec tstamp; /* trigger tstamp */
70 wait_queue_head_t qchange_sleep;
71 struct fasync_struct *fasync;
72} snd_timer_user_t;
73
74/* list of timers */
75static LIST_HEAD(snd_timer_list);
76
77/* list of slave instances */
78static LIST_HEAD(snd_timer_slave_list);
79
80/* lock for slave active lists */
81static DEFINE_SPINLOCK(slave_active_lock);
82
83static DECLARE_MUTEX(register_mutex);
84
85static int snd_timer_free(snd_timer_t *timer);
86static int snd_timer_dev_free(snd_device_t *device);
87static int snd_timer_dev_register(snd_device_t *device);
88static int snd_timer_dev_unregister(snd_device_t *device);
89
90static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left);
91
92/*
93 * create a timer instance with the given owner string.
94 * when timer is not NULL, increments the module counter
95 */
96static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer)
97{
98 snd_timer_instance_t *timeri;
99 timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL);
100 if (timeri == NULL)
101 return NULL;
102 timeri->owner = snd_kmalloc_strdup(owner, GFP_KERNEL);
103 if (! timeri->owner) {
104 kfree(timeri);
105 return NULL;
106 }
107 INIT_LIST_HEAD(&timeri->open_list);
108 INIT_LIST_HEAD(&timeri->active_list);
109 INIT_LIST_HEAD(&timeri->ack_list);
110 INIT_LIST_HEAD(&timeri->slave_list_head);
111 INIT_LIST_HEAD(&timeri->slave_active_head);
112
113 timeri->timer = timer;
114 if (timer && timer->card && !try_module_get(timer->card->module)) {
115 kfree(timeri->owner);
116 kfree(timeri);
117 return NULL;
118 }
119
120 return timeri;
121}
122
123/*
124 * find a timer instance from the given timer id
125 */
126static snd_timer_t *snd_timer_find(snd_timer_id_t *tid)
127{
128 snd_timer_t *timer = NULL;
129 struct list_head *p;
130
131 list_for_each(p, &snd_timer_list) {
132 timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
133
134 if (timer->tmr_class != tid->dev_class)
135 continue;
136 if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
137 timer->tmr_class == SNDRV_TIMER_CLASS_PCM) &&
138 (timer->card == NULL ||
139 timer->card->number != tid->card))
140 continue;
141 if (timer->tmr_device != tid->device)
142 continue;
143 if (timer->tmr_subdevice != tid->subdevice)
144 continue;
145 return timer;
146 }
147 return NULL;
148}
149
150#ifdef CONFIG_KMOD
151
152static void snd_timer_request(snd_timer_id_t *tid)
153{
154 if (! current->fs->root)
155 return;
156 switch (tid->dev_class) {
157 case SNDRV_TIMER_CLASS_GLOBAL:
158 if (tid->device < timer_limit)
159 request_module("snd-timer-%i", tid->device);
160 break;
161 case SNDRV_TIMER_CLASS_CARD:
162 case SNDRV_TIMER_CLASS_PCM:
163 if (tid->card < snd_ecards_limit)
164 request_module("snd-card-%i", tid->card);
165 break;
166 default:
167 break;
168 }
169}
170
171#endif
172
173/*
174 * look for a master instance matching with the slave id of the given slave.
175 * when found, relink the open_link of the slave.
176 *
177 * call this with register_mutex down.
178 */
179static void snd_timer_check_slave(snd_timer_instance_t *slave)
180{
181 snd_timer_t *timer;
182 snd_timer_instance_t *master;
183 struct list_head *p, *q;
184
185 /* FIXME: it's really dumb to look up all entries.. */
186 list_for_each(p, &snd_timer_list) {
187 timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
188 list_for_each(q, &timer->open_list_head) {
189 master = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list);
190 if (slave->slave_class == master->slave_class &&
191 slave->slave_id == master->slave_id) {
192 list_del(&slave->open_list);
193 list_add_tail(&slave->open_list, &master->slave_list_head);
194 spin_lock_irq(&slave_active_lock);
195 slave->master = master;
196 slave->timer = master->timer;
197 spin_unlock_irq(&slave_active_lock);
198 return;
199 }
200 }
201 }
202}
203
204/*
205 * look for slave instances matching with the slave id of the given master.
206 * when found, relink the open_link of slaves.
207 *
208 * call this with register_mutex down.
209 */
210static void snd_timer_check_master(snd_timer_instance_t *master)
211{
212 snd_timer_instance_t *slave;
213 struct list_head *p, *n;
214
215 /* check all pending slaves */
216 list_for_each_safe(p, n, &snd_timer_slave_list) {
217 slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
218 if (slave->slave_class == master->slave_class &&
219 slave->slave_id == master->slave_id) {
220 list_del(p);
221 list_add_tail(p, &master->slave_list_head);
222 spin_lock_irq(&slave_active_lock);
223 slave->master = master;
224 slave->timer = master->timer;
225 if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
226 list_add_tail(&slave->active_list, &master->slave_active_head);
227 spin_unlock_irq(&slave_active_lock);
228 }
229 }
230}
231
232/*
233 * open a timer instance
234 * when opening a master, the slave id must be here given.
235 */
236int snd_timer_open(snd_timer_instance_t **ti,
237 char *owner, snd_timer_id_t *tid,
238 unsigned int slave_id)
239{
240 snd_timer_t *timer;
241 snd_timer_instance_t *timeri = NULL;
242
243 if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
244 /* open a slave instance */
245 if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
246 tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
247 snd_printd("invalid slave class %i\n", tid->dev_sclass);
248 return -EINVAL;
249 }
250 down(&register_mutex);
251 timeri = snd_timer_instance_new(owner, NULL);
252 timeri->slave_class = tid->dev_sclass;
253 timeri->slave_id = tid->device;
254 timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
255 list_add_tail(&timeri->open_list, &snd_timer_slave_list);
256 snd_timer_check_slave(timeri);
257 up(&register_mutex);
258 *ti = timeri;
259 return 0;
260 }
261
262 /* open a master instance */
263 down(&register_mutex);
264 timer = snd_timer_find(tid);
265#ifdef CONFIG_KMOD
266 if (timer == NULL) {
267 up(&register_mutex);
268 snd_timer_request(tid);
269 down(&register_mutex);
270 timer = snd_timer_find(tid);
271 }
272#endif
273 if (timer) {
274 if (!list_empty(&timer->open_list_head)) {
275 timeri = (snd_timer_instance_t *)list_entry(timer->open_list_head.next, snd_timer_instance_t, open_list);
276 if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
277 up(&register_mutex);
278 return -EBUSY;
279 }
280 }
281 timeri = snd_timer_instance_new(owner, timer);
282 if (timeri) {
283 timeri->slave_class = tid->dev_sclass;
284 timeri->slave_id = slave_id;
285 if (list_empty(&timer->open_list_head) && timer->hw.open)
286 timer->hw.open(timer);
287 list_add_tail(&timeri->open_list, &timer->open_list_head);
288 snd_timer_check_master(timeri);
289 }
290 } else {
291 up(&register_mutex);
292 return -ENODEV;
293 }
294 up(&register_mutex);
295 *ti = timeri;
296 return 0;
297}
298
299static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event);
300
301/*
302 * close a timer instance
303 */
304int snd_timer_close(snd_timer_instance_t * timeri)
305{
306 snd_timer_t *timer = NULL;
307 struct list_head *p, *n;
308 snd_timer_instance_t *slave;
309
310 snd_assert(timeri != NULL, return -ENXIO);
311
312 /* force to stop the timer */
313 snd_timer_stop(timeri);
314
315 if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
316 /* wait, until the active callback is finished */
317 spin_lock_irq(&slave_active_lock);
318 while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
319 spin_unlock_irq(&slave_active_lock);
320 udelay(10);
321 spin_lock_irq(&slave_active_lock);
322 }
323 spin_unlock_irq(&slave_active_lock);
324 down(&register_mutex);
325 list_del(&timeri->open_list);
326 up(&register_mutex);
327 } else {
328 timer = timeri->timer;
329 /* wait, until the active callback is finished */
330 spin_lock_irq(&timer->lock);
331 while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
332 spin_unlock_irq(&timer->lock);
333 udelay(10);
334 spin_lock_irq(&timer->lock);
335 }
336 spin_unlock_irq(&timer->lock);
337 down(&register_mutex);
338 list_del(&timeri->open_list);
339 if (timer && list_empty(&timer->open_list_head) && timer->hw.close)
340 timer->hw.close(timer);
341 /* remove slave links */
342 list_for_each_safe(p, n, &timeri->slave_list_head) {
343 slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
344 spin_lock_irq(&slave_active_lock);
345 _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION);
346 list_del(p);
347 list_add_tail(p, &snd_timer_slave_list);
348 slave->master = NULL;
349 slave->timer = NULL;
350 spin_unlock_irq(&slave_active_lock);
351 }
352 up(&register_mutex);
353 }
354 if (timeri->private_free)
355 timeri->private_free(timeri);
356 kfree(timeri->owner);
357 kfree(timeri);
358 if (timer && timer->card)
359 module_put(timer->card->module);
360 return 0;
361}
362
363unsigned long snd_timer_resolution(snd_timer_instance_t * timeri)
364{
365 snd_timer_t * timer;
366
367 if (timeri == NULL)
368 return 0;
369 if ((timer = timeri->timer) != NULL) {
370 if (timer->hw.c_resolution)
371 return timer->hw.c_resolution(timer);
372 return timer->hw.resolution;
373 }
374 return 0;
375}
376
377static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event event)
378{
379 snd_timer_t *timer;
380 unsigned long flags;
381 unsigned long resolution = 0;
382 snd_timer_instance_t *ts;
383 struct list_head *n;
384 struct timespec tstamp;
385
386 snd_timestamp_now(&tstamp, 1);
387 snd_assert(event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE, return);
388 if (event == SNDRV_TIMER_EVENT_START || event == SNDRV_TIMER_EVENT_CONTINUE)
389 resolution = snd_timer_resolution(ti);
390 if (ti->ccallback)
391 ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution);
392 if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
393 return;
394 timer = ti->timer;
395 if (timer == NULL)
396 return;
397 if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
398 return;
399 spin_lock_irqsave(&timer->lock, flags);
400 list_for_each(n, &ti->slave_active_head) {
401 ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list);
402 if (ts->ccallback)
403 ts->ccallback(ti, event + 100, &tstamp, resolution);
404 }
405 spin_unlock_irqrestore(&timer->lock, flags);
406}
407
408static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, unsigned long sticks)
409{
410 list_del(&timeri->active_list);
411 list_add_tail(&timeri->active_list, &timer->active_list_head);
412 if (timer->running) {
413 if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
414 goto __start_now;
415 timer->flags |= SNDRV_TIMER_FLG_RESCHED;
416 timeri->flags |= SNDRV_TIMER_IFLG_START;
417 return 1; /* delayed start */
418 } else {
419 timer->sticks = sticks;
420 timer->hw.start(timer);
421 __start_now:
422 timer->running++;
423 timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
424 return 0;
425 }
426}
427
428static int snd_timer_start_slave(snd_timer_instance_t *timeri)
429{
430 unsigned long flags;
431
432 spin_lock_irqsave(&slave_active_lock, flags);
433 timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
434 if (timeri->master)
435 list_add_tail(&timeri->active_list, &timeri->master->slave_active_head);
436 spin_unlock_irqrestore(&slave_active_lock, flags);
437 return 1; /* delayed start */
438}
439
440/*
441 * start the timer instance
442 */
443int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks)
444{
445 snd_timer_t *timer;
446 int result = -EINVAL;
447 unsigned long flags;
448
449 if (timeri == NULL || ticks < 1)
450 return -EINVAL;
451 if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
452 result = snd_timer_start_slave(timeri);
453 snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
454 return result;
455 }
456 timer = timeri->timer;
457 if (timer == NULL)
458 return -EINVAL;
459 spin_lock_irqsave(&timer->lock, flags);
460 timeri->ticks = timeri->cticks = ticks;
461 timeri->pticks = 0;
462 result = snd_timer_start1(timer, timeri, ticks);
463 spin_unlock_irqrestore(&timer->lock, flags);
464 snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
465 return result;
466}
467
468static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event)
469{
470 snd_timer_t *timer;
471 unsigned long flags;
472
473 snd_assert(timeri != NULL, return -ENXIO);
474
475 if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
476 if (!keep_flag) {
477 spin_lock_irqsave(&slave_active_lock, flags);
478 timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
479 spin_unlock_irqrestore(&slave_active_lock, flags);
480 }
481 goto __end;
482 }
483 timer = timeri->timer;
484 if (!timer)
485 return -EINVAL;
486 spin_lock_irqsave(&timer->lock, flags);
487 list_del_init(&timeri->ack_list);
488 list_del_init(&timeri->active_list);
489 if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) &&
490 !(--timer->running)) {
491 timer->hw.stop(timer);
492 if (timer->flags & SNDRV_TIMER_FLG_RESCHED) {
493 timer->flags &= ~SNDRV_TIMER_FLG_RESCHED;
494 snd_timer_reschedule(timer, 0);
495 if (timer->flags & SNDRV_TIMER_FLG_CHANGE) {
496 timer->flags &= ~SNDRV_TIMER_FLG_CHANGE;
497 timer->hw.start(timer);
498 }
499 }
500 }
501 if (!keep_flag)
502 timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START);
503 spin_unlock_irqrestore(&timer->lock, flags);
504 __end:
505 if (event != SNDRV_TIMER_EVENT_RESOLUTION)
506 snd_timer_notify1(timeri, event);
507 return 0;
508}
509
510/*
511 * stop the timer instance.
512 *
513 * do not call this from the timer callback!
514 */
515int snd_timer_stop(snd_timer_instance_t * timeri)
516{
517 snd_timer_t *timer;
518 unsigned long flags;
519 int err;
520
521 err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP);
522 if (err < 0)
523 return err;
524 timer = timeri->timer;
525 spin_lock_irqsave(&timer->lock, flags);
526 timeri->cticks = timeri->ticks;
527 timeri->pticks = 0;
528 spin_unlock_irqrestore(&timer->lock, flags);
529 return 0;
530}
531
532/*
533 * start again.. the tick is kept.
534 */
535int snd_timer_continue(snd_timer_instance_t * timeri)
536{
537 snd_timer_t *timer;
538 int result = -EINVAL;
539 unsigned long flags;
540
541 if (timeri == NULL)
542 return result;
543 if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
544 return snd_timer_start_slave(timeri);
545 timer = timeri->timer;
546 if (! timer)
547 return -EINVAL;
548 spin_lock_irqsave(&timer->lock, flags);
549 if (!timeri->cticks)
550 timeri->cticks = 1;
551 timeri->pticks = 0;
552 result = snd_timer_start1(timer, timeri, timer->sticks);
553 spin_unlock_irqrestore(&timer->lock, flags);
554 snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE);
555 return result;
556}
557
558/*
559 * pause.. remember the ticks left
560 */
561int snd_timer_pause(snd_timer_instance_t * timeri)
562{
563 return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE);
564}
565
566/*
567 * reschedule the timer
568 *
569 * start pending instances and check the scheduling ticks.
570 * when the scheduling ticks is changed set CHANGE flag to reprogram the timer.
571 */
572static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left)
573{
574 snd_timer_instance_t *ti;
575 unsigned long ticks = ~0UL;
576 struct list_head *p;
577
578 list_for_each(p, &timer->active_list_head) {
579 ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
580 if (ti->flags & SNDRV_TIMER_IFLG_START) {
581 ti->flags &= ~SNDRV_TIMER_IFLG_START;
582 ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
583 timer->running++;
584 }
585 if (ti->flags & SNDRV_TIMER_IFLG_RUNNING) {
586 if (ticks > ti->cticks)
587 ticks = ti->cticks;
588 }
589 }
590 if (ticks == ~0UL) {
591 timer->flags &= ~SNDRV_TIMER_FLG_RESCHED;
592 return;
593 }
594 if (ticks > timer->hw.ticks)
595 ticks = timer->hw.ticks;
596 if (ticks_left != ticks)
597 timer->flags |= SNDRV_TIMER_FLG_CHANGE;
598 timer->sticks = ticks;
599}
600
601/*
602 * timer tasklet
603 *
604 */
605static void snd_timer_tasklet(unsigned long arg)
606{
607 snd_timer_t *timer = (snd_timer_t *) arg;
608 snd_timer_instance_t *ti;
609 struct list_head *p;
610 unsigned long resolution, ticks;
611
612 spin_lock(&timer->lock);
613 /* now process all callbacks */
614 while (!list_empty(&timer->sack_list_head)) {
615 p = timer->sack_list_head.next; /* get first item */
616 ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list);
617
618 /* remove from ack_list and make empty */
619 list_del_init(p);
620
621 ticks = ti->pticks;
622 ti->pticks = 0;
623 resolution = ti->resolution;
624
625 ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
626 spin_unlock(&timer->lock);
627 if (ti->callback)
628 ti->callback(ti, resolution, ticks);
629 spin_lock(&timer->lock);
630 ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
631 }
632 spin_unlock(&timer->lock);
633}
634
635/*
636 * timer interrupt
637 *
638 * ticks_left is usually equal to timer->sticks.
639 *
640 */
641void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left)
642{
643 snd_timer_instance_t *ti, *ts;
644 unsigned long resolution, ticks;
645 struct list_head *p, *q, *n;
646 int use_tasklet = 0;
647
648 if (timer == NULL)
649 return;
650
651 spin_lock(&timer->lock);
652
653 /* remember the current resolution */
654 if (timer->hw.c_resolution)
655 resolution = timer->hw.c_resolution(timer);
656 else
657 resolution = timer->hw.resolution;
658
659 /* loop for all active instances
660 * here we cannot use list_for_each because the active_list of a processed
661 * instance is relinked to done_list_head before callback is called.
662 */
663 list_for_each_safe(p, n, &timer->active_list_head) {
664 ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
665 if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
666 continue;
667 ti->pticks += ticks_left;
668 ti->resolution = resolution;
669 if (ti->cticks < ticks_left)
670 ti->cticks = 0;
671 else
672 ti->cticks -= ticks_left;
673 if (ti->cticks) /* not expired */
674 continue;
675 if (ti->flags & SNDRV_TIMER_IFLG_AUTO) {
676 ti->cticks = ti->ticks;
677 } else {
678 ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
679 if (--timer->running)
680 list_del(p);
681 }
682 if (list_empty(&ti->ack_list)) {
683 if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
684 (ti->flags & SNDRV_TIMER_IFLG_FAST)) {
685 list_add_tail(&ti->ack_list, &timer->ack_list_head);
686 } else {
687 list_add_tail(&ti->ack_list, &timer->sack_list_head);
688 }
689 }
690 list_for_each(q, &ti->slave_active_head) {
691 ts = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, active_list);
692 ts->pticks = ti->pticks;
693 ts->resolution = resolution;
694 if (list_empty(&ts->ack_list)) {
695 if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
696 (ti->flags & SNDRV_TIMER_IFLG_FAST)) {
697 list_add_tail(&ts->ack_list, &timer->ack_list_head);
698 } else {
699 list_add_tail(&ts->ack_list, &timer->sack_list_head);
700 }
701 }
702 }
703 }
704 if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
705 snd_timer_reschedule(timer, ticks_left);
706 if (timer->running) {
707 if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
708 timer->hw.stop(timer);
709 timer->flags |= SNDRV_TIMER_FLG_CHANGE;
710 }
711 if (!(timer->hw.flags & SNDRV_TIMER_HW_AUTO) ||
712 (timer->flags & SNDRV_TIMER_FLG_CHANGE)) {
713 /* restart timer */
714 timer->flags &= ~SNDRV_TIMER_FLG_CHANGE;
715 timer->hw.start(timer);
716 }
717 } else {
718 timer->hw.stop(timer);
719 }
720
721 /* now process all fast callbacks */
722 while (!list_empty(&timer->ack_list_head)) {
723 p = timer->ack_list_head.next; /* get first item */
724 ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list);
725
726 /* remove from ack_list and make empty */
727 list_del_init(p);
728
729 ticks = ti->pticks;
730 ti->pticks = 0;
731
732 ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
733 spin_unlock(&timer->lock);
734 if (ti->callback)
735 ti->callback(ti, resolution, ticks);
736 spin_lock(&timer->lock);
737 ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
738 }
739
740 /* do we have any slow callbacks? */
741 use_tasklet = !list_empty(&timer->sack_list_head);
742 spin_unlock(&timer->lock);
743
744 if (use_tasklet)
745 tasklet_hi_schedule(&timer->task_queue);
746}
747
748/*
749
750 */
751
752int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer)
753{
754 snd_timer_t *timer;
755 int err;
756 static snd_device_ops_t ops = {
757 .dev_free = snd_timer_dev_free,
758 .dev_register = snd_timer_dev_register,
759 .dev_unregister = snd_timer_dev_unregister
760 };
761
762 snd_assert(tid != NULL, return -EINVAL);
763 snd_assert(rtimer != NULL, return -EINVAL);
764 *rtimer = NULL;
765 timer = kcalloc(1, sizeof(*timer), GFP_KERNEL);
766 if (timer == NULL)
767 return -ENOMEM;
768 timer->tmr_class = tid->dev_class;
769 timer->card = card;
770 timer->tmr_device = tid->device;
771 timer->tmr_subdevice = tid->subdevice;
772 if (id)
773 strlcpy(timer->id, id, sizeof(timer->id));
774 INIT_LIST_HEAD(&timer->device_list);
775 INIT_LIST_HEAD(&timer->open_list_head);
776 INIT_LIST_HEAD(&timer->active_list_head);
777 INIT_LIST_HEAD(&timer->ack_list_head);
778 INIT_LIST_HEAD(&timer->sack_list_head);
779 spin_lock_init(&timer->lock);
780 tasklet_init(&timer->task_queue, snd_timer_tasklet, (unsigned long)timer);
781 if (card != NULL) {
782 if ((err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops)) < 0) {
783 snd_timer_free(timer);
784 return err;
785 }
786 }
787 *rtimer = timer;
788 return 0;
789}
790
791static int snd_timer_free(snd_timer_t *timer)
792{
793 snd_assert(timer != NULL, return -ENXIO);
794 if (timer->private_free)
795 timer->private_free(timer);
796 kfree(timer);
797 return 0;
798}
799
800int snd_timer_dev_free(snd_device_t *device)
801{
802 snd_timer_t *timer = device->device_data;
803 return snd_timer_free(timer);
804}
805
806int snd_timer_dev_register(snd_device_t *dev)
807{
808 snd_timer_t *timer = dev->device_data;
809 snd_timer_t *timer1;
810 struct list_head *p;
811
812 snd_assert(timer != NULL && timer->hw.start != NULL && timer->hw.stop != NULL, return -ENXIO);
813 if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
814 !timer->hw.resolution && timer->hw.c_resolution == NULL)
815 return -EINVAL;
816
817 down(&register_mutex);
818 list_for_each(p, &snd_timer_list) {
819 timer1 = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
820 if (timer1->tmr_class > timer->tmr_class)
821 break;
822 if (timer1->tmr_class < timer->tmr_class)
823 continue;
824 if (timer1->card && timer->card) {
825 if (timer1->card->number > timer->card->number)
826 break;
827 if (timer1->card->number < timer->card->number)
828 continue;
829 }
830 if (timer1->tmr_device > timer->tmr_device)
831 break;
832 if (timer1->tmr_device < timer->tmr_device)
833 continue;
834 if (timer1->tmr_subdevice > timer->tmr_subdevice)
835 break;
836 if (timer1->tmr_subdevice < timer->tmr_subdevice)
837 continue;
838 /* conflicts.. */
839 up(&register_mutex);
840 return -EBUSY;
841 }
842 list_add_tail(&timer->device_list, p);
843 up(&register_mutex);
844 return 0;
845}
846
847int snd_timer_unregister(snd_timer_t *timer)
848{
849 struct list_head *p, *n;
850 snd_timer_instance_t *ti;
851
852 snd_assert(timer != NULL, return -ENXIO);
853 down(&register_mutex);
854 if (! list_empty(&timer->open_list_head)) {
855 snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer);
856 list_for_each_safe(p, n, &timer->open_list_head) {
857 list_del_init(p);
858 ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list);
859 ti->timer = NULL;
860 }
861 }
862 list_del(&timer->device_list);
863 up(&register_mutex);
864 return snd_timer_free(timer);
865}
866
867static int snd_timer_dev_unregister(snd_device_t *device)
868{
869 snd_timer_t *timer = device->device_data;
870 return snd_timer_unregister(timer);
871}
872
873void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp)
874{
875 unsigned long flags;
876 unsigned long resolution = 0;
877 snd_timer_instance_t *ti, *ts;
878 struct list_head *p, *n;
879
880 snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);
881 snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
882 spin_lock_irqsave(&timer->lock, flags);
883 if (event == SNDRV_TIMER_EVENT_MSTART || event == SNDRV_TIMER_EVENT_MCONTINUE) {
884 if (timer->hw.c_resolution)
885 resolution = timer->hw.c_resolution(timer);
886 else
887 resolution = timer->hw.resolution;
888 }
889 list_for_each(p, &timer->active_list_head) {
890 ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, active_list);
891 if (ti->ccallback)
892 ti->ccallback(ti, event, tstamp, resolution);
893 list_for_each(n, &ti->slave_active_head) {
894 ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, active_list);
895 if (ts->ccallback)
896 ts->ccallback(ts, event, tstamp, resolution);
897 }
898 }
899 spin_unlock_irqrestore(&timer->lock, flags);
900}
901
902/*
903 * exported functions for global timers
904 */
905int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer)
906{
907 snd_timer_id_t tid;
908
909 tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
910 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
911 tid.card = -1;
912 tid.device = device;
913 tid.subdevice = 0;
914 return snd_timer_new(NULL, id, &tid, rtimer);
915}
916
917int snd_timer_global_free(snd_timer_t *timer)
918{
919 return snd_timer_free(timer);
920}
921
922int snd_timer_global_register(snd_timer_t *timer)
923{
924 snd_device_t dev;
925
926 memset(&dev, 0, sizeof(dev));
927 dev.device_data = timer;
928 return snd_timer_dev_register(&dev);
929}
930
931int snd_timer_global_unregister(snd_timer_t *timer)
932{
933 return snd_timer_unregister(timer);
934}
935
936/*
937 * System timer
938 */
939
940struct snd_timer_system_private {
941 struct timer_list tlist;
942 struct timer * timer;
943 unsigned long last_expires;
944 unsigned long last_jiffies;
945 unsigned long correction;
946};
947
948unsigned int snd_timer_system_resolution(void)
949{
950 return 1000000000L / HZ;
951}
952
953static void snd_timer_s_function(unsigned long data)
954{
955 snd_timer_t *timer = (snd_timer_t *)data;
956 struct snd_timer_system_private *priv = timer->private_data;
957 unsigned long jiff = jiffies;
958 if (time_after(jiff, priv->last_expires))
959 priv->correction = (long)jiff - (long)priv->last_expires;
960 snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
961}
962
963static int snd_timer_s_start(snd_timer_t * timer)
964{
965 struct snd_timer_system_private *priv;
966 unsigned long njiff;
967
968 priv = (struct snd_timer_system_private *) timer->private_data;
969 njiff = (priv->last_jiffies = jiffies);
970 if (priv->correction > timer->sticks - 1) {
971 priv->correction -= timer->sticks - 1;
972 njiff++;
973 } else {
974 njiff += timer->sticks - priv->correction;
975 priv->correction -= timer->sticks;
976 }
977 priv->last_expires = priv->tlist.expires = njiff;
978 add_timer(&priv->tlist);
979 return 0;
980}
981
982static int snd_timer_s_stop(snd_timer_t * timer)
983{
984 struct snd_timer_system_private *priv;
985 unsigned long jiff;
986
987 priv = (struct snd_timer_system_private *) timer->private_data;
988 del_timer(&priv->tlist);
989 jiff = jiffies;
990 if (time_before(jiff, priv->last_expires))
991 timer->sticks = priv->last_expires - jiff;
992 else
993 timer->sticks = 1;
994 return 0;
995}
996
997static struct _snd_timer_hardware snd_timer_system =
998{
999 .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
1000 .resolution = 1000000000L / HZ,
1001 .ticks = 10000000L,
1002 .start = snd_timer_s_start,
1003 .stop = snd_timer_s_stop
1004};
1005
1006static void snd_timer_free_system(snd_timer_t *timer)
1007{
1008 kfree(timer->private_data);
1009}
1010
1011static int snd_timer_register_system(void)
1012{
1013 snd_timer_t *timer;
1014 struct snd_timer_system_private *priv;
1015 int err;
1016
1017 if ((err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer)) < 0)
1018 return err;
1019 strcpy(timer->name, "system timer");
1020 timer->hw = snd_timer_system;
1021 priv = kcalloc(1, sizeof(*priv), GFP_KERNEL);
1022 if (priv == NULL) {
1023 snd_timer_free(timer);
1024 return -ENOMEM;
1025 }
1026 init_timer(&priv->tlist);
1027 priv->tlist.function = snd_timer_s_function;
1028 priv->tlist.data = (unsigned long) timer;
1029 timer->private_data = priv;
1030 timer->private_free = snd_timer_free_system;
1031 return snd_timer_global_register(timer);
1032}
1033
1034/*
1035 * Info interface
1036 */
1037
1038static void snd_timer_proc_read(snd_info_entry_t *entry,
1039 snd_info_buffer_t * buffer)
1040{
1041 unsigned long flags;
1042 snd_timer_t *timer;
1043 snd_timer_instance_t *ti;
1044 struct list_head *p, *q;
1045
1046 down(&register_mutex);
1047 list_for_each(p, &snd_timer_list) {
1048 timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
1049 switch (timer->tmr_class) {
1050 case SNDRV_TIMER_CLASS_GLOBAL:
1051 snd_iprintf(buffer, "G%i: ", timer->tmr_device);
1052 break;
1053 case SNDRV_TIMER_CLASS_CARD:
1054 snd_iprintf(buffer, "C%i-%i: ", timer->card->number, timer->tmr_device);
1055 break;
1056 case SNDRV_TIMER_CLASS_PCM:
1057 snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, timer->tmr_device, timer->tmr_subdevice);
1058 break;
1059 default:
1060 snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, timer->card ? timer->card->number : -1, timer->tmr_device, timer->tmr_subdevice);
1061 }
1062 snd_iprintf(buffer, "%s :", timer->name);
1063 if (timer->hw.resolution)
1064 snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks);
1065 if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
1066 snd_iprintf(buffer, " SLAVE");
1067 snd_iprintf(buffer, "\n");
1068 spin_lock_irqsave(&timer->lock, flags);
1069 list_for_each(q, &timer->open_list_head) {
1070 ti = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list);
1071 snd_iprintf(buffer, " Client %s : %s : lost interrupts %li\n",
1072 ti->owner ? ti->owner : "unknown",
1073 ti->flags & (SNDRV_TIMER_IFLG_START|SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped",
1074 ti->lost);
1075 }
1076 spin_unlock_irqrestore(&timer->lock, flags);
1077 }
1078 up(&register_mutex);
1079}
1080
1081/*
1082 * USER SPACE interface
1083 */
1084
1085static void snd_timer_user_interrupt(snd_timer_instance_t *timeri,
1086 unsigned long resolution,
1087 unsigned long ticks)
1088{
1089 snd_timer_user_t *tu = timeri->callback_data;
1090 snd_timer_read_t *r;
1091 int prev;
1092
1093 spin_lock(&tu->qlock);
1094 if (tu->qused > 0) {
1095 prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
1096 r = &tu->queue[prev];
1097 if (r->resolution == resolution) {
1098 r->ticks += ticks;
1099 goto __wake;
1100 }
1101 }
1102 if (tu->qused >= tu->queue_size) {
1103 tu->overrun++;
1104 } else {
1105 r = &tu->queue[tu->qtail++];
1106 tu->qtail %= tu->queue_size;
1107 r->resolution = resolution;
1108 r->ticks = ticks;
1109 tu->qused++;
1110 }
1111 __wake:
1112 spin_unlock(&tu->qlock);
1113 kill_fasync(&tu->fasync, SIGIO, POLL_IN);
1114 wake_up(&tu->qchange_sleep);
1115}
1116
1117static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_tread_t *tread)
1118{
1119 if (tu->qused >= tu->queue_size) {
1120 tu->overrun++;
1121 } else {
1122 memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread));
1123 tu->qtail %= tu->queue_size;
1124 tu->qused++;
1125 }
1126}
1127
1128static void snd_timer_user_ccallback(snd_timer_instance_t *timeri,
1129 enum sndrv_timer_event event,
1130 struct timespec *tstamp,
1131 unsigned long resolution)
1132{
1133 snd_timer_user_t *tu = timeri->callback_data;
1134 snd_timer_tread_t r1;
1135
1136 if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE)
1137 tu->tstamp = *tstamp;
1138 if ((tu->filter & (1 << event)) == 0 || !tu->tread)
1139 return;
1140 r1.event = event;
1141 r1.tstamp = *tstamp;
1142 r1.val = resolution;
1143 spin_lock(&tu->qlock);
1144 snd_timer_user_append_to_tqueue(tu, &r1);
1145 spin_unlock(&tu->qlock);
1146 kill_fasync(&tu->fasync, SIGIO, POLL_IN);
1147 wake_up(&tu->qchange_sleep);
1148}
1149
1150static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri,
1151 unsigned long resolution,
1152 unsigned long ticks)
1153{
1154 snd_timer_user_t *tu = timeri->callback_data;
1155 snd_timer_tread_t *r, r1;
1156 struct timespec tstamp;
1157 int prev, append = 0;
1158
1159 snd_timestamp_zero(&tstamp);
1160 spin_lock(&tu->qlock);
1161 if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION)|(1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
1162 spin_unlock(&tu->qlock);
1163 return;
1164 }
1165 if (tu->last_resolution != resolution || ticks > 0)
1166 snd_timestamp_now(&tstamp, 1);
1167 if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) {
1168 r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
1169 r1.tstamp = tstamp;
1170 r1.val = resolution;
1171 snd_timer_user_append_to_tqueue(tu, &r1);
1172 tu->last_resolution = resolution;
1173 append++;
1174 }
1175 if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
1176 goto __wake;
1177 if (ticks == 0)
1178 goto __wake;
1179 if (tu->qused > 0) {
1180 prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
1181 r = &tu->tqueue[prev];
1182 if (r->event == SNDRV_TIMER_EVENT_TICK) {
1183 r->tstamp = tstamp;
1184 r->val += ticks;
1185 append++;
1186 goto __wake;
1187 }
1188 }
1189 r1.event = SNDRV_TIMER_EVENT_TICK;
1190 r1.tstamp = tstamp;
1191 r1.val = ticks;
1192 snd_timer_user_append_to_tqueue(tu, &r1);
1193 append++;
1194 __wake:
1195 spin_unlock(&tu->qlock);
1196 if (append == 0)
1197 return;
1198 kill_fasync(&tu->fasync, SIGIO, POLL_IN);
1199 wake_up(&tu->qchange_sleep);
1200}
1201
1202static int snd_timer_user_open(struct inode *inode, struct file *file)
1203{
1204 snd_timer_user_t *tu;
1205
1206 tu = kcalloc(1, sizeof(*tu), GFP_KERNEL);
1207 if (tu == NULL)
1208 return -ENOMEM;
1209 spin_lock_init(&tu->qlock);
1210 init_waitqueue_head(&tu->qchange_sleep);
1211 tu->ticks = 1;
1212 tu->queue_size = 128;
1213 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
1214 if (tu->queue == NULL) {
1215 kfree(tu);
1216 return -ENOMEM;
1217 }
1218 file->private_data = tu;
1219 return 0;
1220}
1221
1222static int snd_timer_user_release(struct inode *inode, struct file *file)
1223{
1224 snd_timer_user_t *tu;
1225
1226 if (file->private_data) {
1227 tu = file->private_data;
1228 file->private_data = NULL;
1229 fasync_helper(-1, file, 0, &tu->fasync);
1230 if (tu->timeri)
1231 snd_timer_close(tu->timeri);
1232 kfree(tu->queue);
1233 kfree(tu->tqueue);
1234 kfree(tu);
1235 }
1236 return 0;
1237}
1238
1239static void snd_timer_user_zero_id(snd_timer_id_t *id)
1240{
1241 id->dev_class = SNDRV_TIMER_CLASS_NONE;
1242 id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1243 id->card = -1;
1244 id->device = -1;
1245 id->subdevice = -1;
1246}
1247
1248static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer)
1249{
1250 id->dev_class = timer->tmr_class;
1251 id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
1252 id->card = timer->card ? timer->card->number : -1;
1253 id->device = timer->tmr_device;
1254 id->subdevice = timer->tmr_subdevice;
1255}
1256
1257static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
1258{
1259 snd_timer_id_t id;
1260 snd_timer_t *timer;
1261 struct list_head *p;
1262
1263 if (copy_from_user(&id, _tid, sizeof(id)))
1264 return -EFAULT;
1265 down(&register_mutex);
1266 if (id.dev_class < 0) { /* first item */
1267 if (list_empty(&snd_timer_list))
1268 snd_timer_user_zero_id(&id);
1269 else {
1270 timer = (snd_timer_t *)list_entry(snd_timer_list.next, snd_timer_t, device_list);
1271 snd_timer_user_copy_id(&id, timer);
1272 }
1273 } else {
1274 switch (id.dev_class) {
1275 case SNDRV_TIMER_CLASS_GLOBAL:
1276 id.device = id.device < 0 ? 0 : id.device + 1;
1277 list_for_each(p, &snd_timer_list) {
1278 timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
1279 if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {
1280 snd_timer_user_copy_id(&id, timer);
1281 break;
1282 }
1283 if (timer->tmr_device >= id.device) {
1284 snd_timer_user_copy_id(&id, timer);
1285 break;
1286 }
1287 }
1288 if (p == &snd_timer_list)
1289 snd_timer_user_zero_id(&id);
1290 break;
1291 case SNDRV_TIMER_CLASS_CARD:
1292 case SNDRV_TIMER_CLASS_PCM:
1293 if (id.card < 0) {
1294 id.card = 0;
1295 } else {
1296 if (id.card < 0) {
1297 id.card = 0;
1298 } else {
1299 if (id.device < 0) {
1300 id.device = 0;
1301 } else {
1302 id.subdevice = id.subdevice < 0 ? 0 : id.subdevice + 1;
1303 }
1304 }
1305 }
1306 list_for_each(p, &snd_timer_list) {
1307 timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
1308 if (timer->tmr_class > id.dev_class) {
1309 snd_timer_user_copy_id(&id, timer);
1310 break;
1311 }
1312 if (timer->tmr_class < id.dev_class)
1313 continue;
1314 if (timer->card->number > id.card) {
1315 snd_timer_user_copy_id(&id, timer);
1316 break;
1317 }
1318 if (timer->card->number < id.card)
1319 continue;
1320 if (timer->tmr_device > id.device) {
1321 snd_timer_user_copy_id(&id, timer);
1322 break;
1323 }
1324 if (timer->tmr_device < id.device)
1325 continue;
1326 if (timer->tmr_subdevice > id.subdevice) {
1327 snd_timer_user_copy_id(&id, timer);
1328 break;
1329 }
1330 if (timer->tmr_subdevice < id.subdevice)
1331 continue;
1332 snd_timer_user_copy_id(&id, timer);
1333 break;
1334 }
1335 if (p == &snd_timer_list)
1336 snd_timer_user_zero_id(&id);
1337 break;
1338 default:
1339 snd_timer_user_zero_id(&id);
1340 }
1341 }
1342 up(&register_mutex);
1343 if (copy_to_user(_tid, &id, sizeof(*_tid)))
1344 return -EFAULT;
1345 return 0;
1346}
1347
1348static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo)
1349{
1350 snd_timer_ginfo_t *ginfo;
1351 snd_timer_id_t tid;
1352 snd_timer_t *t;
1353 struct list_head *p;
1354 int err = 0;
1355
1356 ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL);
1357 if (! ginfo)
1358 return -ENOMEM;
1359 if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) {
1360 kfree(ginfo);
1361 return -EFAULT;
1362 }
1363 tid = ginfo->tid;
1364 memset(ginfo, 0, sizeof(*ginfo));
1365 ginfo->tid = tid;
1366 down(&register_mutex);
1367 t = snd_timer_find(&tid);
1368 if (t != NULL) {
1369 ginfo->card = t->card ? t->card->number : -1;
1370 if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
1371 ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
1372 strlcpy(ginfo->id, t->id, sizeof(ginfo->id));
1373 strlcpy(ginfo->name, t->name, sizeof(ginfo->name));
1374 ginfo->resolution = t->hw.resolution;
1375 if (t->hw.resolution_min > 0) {
1376 ginfo->resolution_min = t->hw.resolution_min;
1377 ginfo->resolution_max = t->hw.resolution_max;
1378 }
1379 list_for_each(p, &t->open_list_head) {
1380 ginfo->clients++;
1381 }
1382 } else {
1383 err = -ENODEV;
1384 }
1385 up(&register_mutex);
1386 if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
1387 err = -EFAULT;
1388 kfree(ginfo);
1389 return err;
1390}
1391
1392static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams)
1393{
1394 snd_timer_gparams_t gparams;
1395 snd_timer_t *t;
1396 int err;
1397
1398 if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
1399 return -EFAULT;
1400 down(&register_mutex);
1401 t = snd_timer_find(&gparams.tid);
1402 if (t != NULL) {
1403 if (list_empty(&t->open_list_head)) {
1404 if (t->hw.set_period)
1405 err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
1406 else
1407 err = -ENOSYS;
1408 } else {
1409 err = -EBUSY;
1410 }
1411 } else {
1412 err = -ENODEV;
1413 }
1414 up(&register_mutex);
1415 return err;
1416}
1417
1418static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus)
1419{
1420 snd_timer_gstatus_t gstatus;
1421 snd_timer_id_t tid;
1422 snd_timer_t *t;
1423 int err = 0;
1424
1425 if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
1426 return -EFAULT;
1427 tid = gstatus.tid;
1428 memset(&gstatus, 0, sizeof(gstatus));
1429 gstatus.tid = tid;
1430 down(&register_mutex);
1431 t = snd_timer_find(&tid);
1432 if (t != NULL) {
1433 if (t->hw.c_resolution)
1434 gstatus.resolution = t->hw.c_resolution(t);
1435 else
1436 gstatus.resolution = t->hw.resolution;
1437 if (t->hw.precise_resolution) {
1438 t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den);
1439 } else {
1440 gstatus.resolution_num = gstatus.resolution;
1441 gstatus.resolution_den = 1000000000uL;
1442 }
1443 } else {
1444 err = -ENODEV;
1445 }
1446 up(&register_mutex);
1447 if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
1448 err = -EFAULT;
1449 return err;
1450}
1451
1452static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect)
1453{
1454 snd_timer_user_t *tu;
1455 snd_timer_select_t tselect;
1456 char str[32];
1457 int err;
1458
1459 tu = file->private_data;
1460 if (tu->timeri)
1461 snd_timer_close(tu->timeri);
1462 if (copy_from_user(&tselect, _tselect, sizeof(tselect)))
1463 return -EFAULT;
1464 sprintf(str, "application %i", current->pid);
1465 if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
1466 tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
1467 if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0)
1468 return err;
1469
1470 if (tu->queue) {
1471 kfree(tu->queue);
1472 tu->queue = NULL;
1473 }
1474 if (tu->tqueue) {
1475 kfree(tu->tqueue);
1476 tu->tqueue = NULL;
1477 }
1478 if (tu->tread) {
1479 tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
1480 if (tu->tqueue == NULL) {
1481 snd_timer_close(tu->timeri);
1482 return -ENOMEM;
1483 }
1484 } else {
1485 tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
1486 if (tu->queue == NULL) {
1487 snd_timer_close(tu->timeri);
1488 return -ENOMEM;
1489 }
1490 }
1491
1492 tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
1493 tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
1494 tu->timeri->ccallback = snd_timer_user_ccallback;
1495 tu->timeri->callback_data = (void *)tu;
1496 return 0;
1497}
1498
1499static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
1500{
1501 snd_timer_user_t *tu;
1502 snd_timer_info_t *info;
1503 snd_timer_t *t;
1504 int err = 0;
1505
1506 tu = file->private_data;
1507 snd_assert(tu->timeri != NULL, return -ENXIO);
1508 t = tu->timeri->timer;
1509 snd_assert(t != NULL, return -ENXIO);
1510
1511 info = kcalloc(1, sizeof(*info), GFP_KERNEL);
1512 if (! info)
1513 return -ENOMEM;
1514 info->card = t->card ? t->card->number : -1;
1515 if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
1516 info->flags |= SNDRV_TIMER_FLG_SLAVE;
1517 strlcpy(info->id, t->id, sizeof(info->id));
1518 strlcpy(info->name, t->name, sizeof(info->name));
1519 info->resolution = t->hw.resolution;
1520 if (copy_to_user(_info, info, sizeof(*_info)))
1521 err = -EFAULT;
1522 kfree(info);
1523 return err;
1524}
1525
1526static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params)
1527{
1528 snd_timer_user_t *tu;
1529 snd_timer_params_t params;
1530 snd_timer_t *t;
1531 snd_timer_read_t *tr;
1532 snd_timer_tread_t *ttr;
1533 int err;
1534
1535 tu = file->private_data;
1536 snd_assert(tu->timeri != NULL, return -ENXIO);
1537 t = tu->timeri->timer;
1538 snd_assert(t != NULL, return -ENXIO);
1539 if (copy_from_user(&params, _params, sizeof(params)))
1540 return -EFAULT;
1541 if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
1542 err = -EINVAL;
1543 goto _end;
1544 }
1545 if (params.queue_size > 0 && (params.queue_size < 32 || params.queue_size > 1024)) {
1546 err = -EINVAL;
1547 goto _end;
1548 }
1549 if (params.filter & ~((1<<SNDRV_TIMER_EVENT_RESOLUTION)|
1550 (1<<SNDRV_TIMER_EVENT_TICK)|
1551 (1<<SNDRV_TIMER_EVENT_START)|
1552 (1<<SNDRV_TIMER_EVENT_STOP)|
1553 (1<<SNDRV_TIMER_EVENT_CONTINUE)|
1554 (1<<SNDRV_TIMER_EVENT_PAUSE)|
1555 (1<<SNDRV_TIMER_EVENT_MSTART)|
1556 (1<<SNDRV_TIMER_EVENT_MSTOP)|
1557 (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
1558 (1<<SNDRV_TIMER_EVENT_MPAUSE))) {
1559 err = -EINVAL;
1560 goto _end;
1561 }
1562 snd_timer_stop(tu->timeri);
1563 spin_lock_irq(&t->lock);
1564 tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
1565 SNDRV_TIMER_IFLG_EXCLUSIVE|
1566 SNDRV_TIMER_IFLG_EARLY_EVENT);
1567 if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
1568 tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
1569 if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
1570 tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
1571 if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
1572 tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
1573 spin_unlock_irq(&t->lock);
1574 if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) {
1575 if (tu->tread) {
1576 ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
1577 if (ttr) {
1578 kfree(tu->tqueue);
1579 tu->queue_size = params.queue_size;
1580 tu->tqueue = ttr;
1581 }
1582 } else {
1583 tr = (snd_timer_read_t *)kmalloc(params.queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
1584 if (tr) {
1585 kfree(tu->queue);
1586 tu->queue_size = params.queue_size;
1587 tu->queue = tr;
1588 }
1589 }
1590 }
1591 tu->qhead = tu->qtail = tu->qused = 0;
1592 if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
1593 if (tu->tread) {
1594 snd_timer_tread_t tread;
1595 tread.event = SNDRV_TIMER_EVENT_EARLY;
1596 tread.tstamp.tv_sec = 0;
1597 tread.tstamp.tv_nsec = 0;
1598 tread.val = 0;
1599 snd_timer_user_append_to_tqueue(tu, &tread);
1600 } else {
1601 snd_timer_read_t *r = &tu->queue[0];
1602 r->resolution = 0;
1603 r->ticks = 0;
1604 tu->qused++;
1605 tu->qtail++;
1606 }
1607
1608 }
1609 tu->filter = params.filter;
1610 tu->ticks = params.ticks;
1611 err = 0;
1612 _end:
1613 if (copy_to_user(_params, &params, sizeof(params)))
1614 return -EFAULT;
1615 return err;
1616}
1617
1618static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status)
1619{
1620 snd_timer_user_t *tu;
1621 snd_timer_status_t status;
1622
1623 tu = file->private_data;
1624 snd_assert(tu->timeri != NULL, return -ENXIO);
1625 memset(&status, 0, sizeof(status));
1626 status.tstamp = tu->tstamp;
1627 status.resolution = snd_timer_resolution(tu->timeri);
1628 status.lost = tu->timeri->lost;
1629 status.overrun = tu->overrun;
1630 spin_lock_irq(&tu->qlock);
1631 status.queue = tu->qused;
1632 spin_unlock_irq(&tu->qlock);
1633 if (copy_to_user(_status, &status, sizeof(status)))
1634 return -EFAULT;
1635 return 0;
1636}
1637
1638static int snd_timer_user_start(struct file *file)
1639{
1640 int err;
1641 snd_timer_user_t *tu;
1642
1643 tu = file->private_data;
1644 snd_assert(tu->timeri != NULL, return -ENXIO);
1645 snd_timer_stop(tu->timeri);
1646 tu->timeri->lost = 0;
1647 tu->last_resolution = 0;
1648 return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0;
1649}
1650
1651static int snd_timer_user_stop(struct file *file)
1652{
1653 int err;
1654 snd_timer_user_t *tu;
1655
1656 tu = file->private_data;
1657 snd_assert(tu->timeri != NULL, return -ENXIO);
1658 return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
1659}
1660
1661static int snd_timer_user_continue(struct file *file)
1662{
1663 int err;
1664 snd_timer_user_t *tu;
1665
1666 tu = file->private_data;
1667 snd_assert(tu->timeri != NULL, return -ENXIO);
1668 tu->timeri->lost = 0;
1669 return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
1670}
1671
1672static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1673{
1674 snd_timer_user_t *tu;
1675 void __user *argp = (void __user *)arg;
1676 int __user *p = argp;
1677
1678 tu = file->private_data;
1679 switch (cmd) {
1680 case SNDRV_TIMER_IOCTL_PVERSION:
1681 return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;
1682 case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
1683 return snd_timer_user_next_device(argp);
1684 case SNDRV_TIMER_IOCTL_TREAD:
1685 {
1686 int xarg;
1687
1688 if (tu->timeri) /* too late */
1689 return -EBUSY;
1690 if (get_user(xarg, p))
1691 return -EFAULT;
1692 tu->tread = xarg ? 1 : 0;
1693 return 0;
1694 }
1695 case SNDRV_TIMER_IOCTL_GINFO:
1696 return snd_timer_user_ginfo(file, argp);
1697 case SNDRV_TIMER_IOCTL_GPARAMS:
1698 return snd_timer_user_gparams(file, argp);
1699 case SNDRV_TIMER_IOCTL_GSTATUS:
1700 return snd_timer_user_gstatus(file, argp);
1701 case SNDRV_TIMER_IOCTL_SELECT:
1702 return snd_timer_user_tselect(file, argp);
1703 case SNDRV_TIMER_IOCTL_INFO:
1704 return snd_timer_user_info(file, argp);
1705 case SNDRV_TIMER_IOCTL_PARAMS:
1706 return snd_timer_user_params(file, argp);
1707 case SNDRV_TIMER_IOCTL_STATUS:
1708 return snd_timer_user_status(file, argp);
1709 case SNDRV_TIMER_IOCTL_START:
1710 return snd_timer_user_start(file);
1711 case SNDRV_TIMER_IOCTL_STOP:
1712 return snd_timer_user_stop(file);
1713 case SNDRV_TIMER_IOCTL_CONTINUE:
1714 return snd_timer_user_continue(file);
1715 }
1716 return -ENOTTY;
1717}
1718
1719static int snd_timer_user_fasync(int fd, struct file * file, int on)
1720{
1721 snd_timer_user_t *tu;
1722 int err;
1723
1724 tu = file->private_data;
1725 err = fasync_helper(fd, file, on, &tu->fasync);
1726 if (err < 0)
1727 return err;
1728 return 0;
1729}
1730
1731static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_t count, loff_t *offset)
1732{
1733 snd_timer_user_t *tu;
1734 long result = 0, unit;
1735 int err = 0;
1736
1737 tu = file->private_data;
1738 unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t);
1739 spin_lock_irq(&tu->qlock);
1740 while ((long)count - result >= unit) {
1741 while (!tu->qused) {
1742 wait_queue_t wait;
1743
1744 if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
1745 err = -EAGAIN;
1746 break;
1747 }
1748
1749 set_current_state(TASK_INTERRUPTIBLE);
1750 init_waitqueue_entry(&wait, current);
1751 add_wait_queue(&tu->qchange_sleep, &wait);
1752
1753 spin_unlock_irq(&tu->qlock);
1754 schedule();
1755 spin_lock_irq(&tu->qlock);
1756
1757 remove_wait_queue(&tu->qchange_sleep, &wait);
1758
1759 if (signal_pending(current)) {
1760 err = -ERESTARTSYS;
1761 break;
1762 }
1763 }
1764
1765 spin_unlock_irq(&tu->qlock);
1766 if (err < 0)
1767 goto _error;
1768
1769 if (tu->tread) {
1770 if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) {
1771 err = -EFAULT;
1772 goto _error;
1773 }
1774 } else {
1775 if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) {
1776 err = -EFAULT;
1777 goto _error;
1778 }
1779 }
1780
1781 tu->qhead %= tu->queue_size;
1782
1783 result += unit;
1784 buffer += unit;
1785
1786 spin_lock_irq(&tu->qlock);
1787 tu->qused--;
1788 }
1789 spin_unlock_irq(&tu->qlock);
1790 _error:
1791 return result > 0 ? result : err;
1792}
1793
1794static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
1795{
1796 unsigned int mask;
1797 snd_timer_user_t *tu;
1798
1799 tu = file->private_data;
1800
1801 poll_wait(file, &tu->qchange_sleep, wait);
1802
1803 mask = 0;
1804 if (tu->qused)
1805 mask |= POLLIN | POLLRDNORM;
1806
1807 return mask;
1808}
1809
1810#ifdef CONFIG_COMPAT
1811#include "timer_compat.c"
1812#else
1813#define snd_timer_user_ioctl_compat NULL
1814#endif
1815
1816static struct file_operations snd_timer_f_ops =
1817{
1818 .owner = THIS_MODULE,
1819 .read = snd_timer_user_read,
1820 .open = snd_timer_user_open,
1821 .release = snd_timer_user_release,
1822 .poll = snd_timer_user_poll,
1823 .unlocked_ioctl = snd_timer_user_ioctl,
1824 .compat_ioctl = snd_timer_user_ioctl_compat,
1825 .fasync = snd_timer_user_fasync,
1826};
1827
1828static snd_minor_t snd_timer_reg =
1829{
1830 .comment = "timer",
1831 .f_ops = &snd_timer_f_ops,
1832};
1833
1834/*
1835 * ENTRY functions
1836 */
1837
1838static snd_info_entry_t *snd_timer_proc_entry = NULL;
1839
1840static int __init alsa_timer_init(void)
1841{
1842 int err;
1843 snd_info_entry_t *entry;
1844
1845#ifdef SNDRV_OSS_INFO_DEV_TIMERS
1846 snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer");
1847#endif
1848 if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != NULL) {
1849 entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128;
1850 entry->c.text.read = snd_timer_proc_read;
1851 if (snd_info_register(entry) < 0) {
1852 snd_info_free_entry(entry);
1853 entry = NULL;
1854 }
1855 }
1856 snd_timer_proc_entry = entry;
1857 if ((err = snd_timer_register_system()) < 0)
1858 snd_printk(KERN_ERR "unable to register system timer (%i)\n", err);
1859 if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER,
1860 NULL, 0, &snd_timer_reg, "timer"))<0)
1861 snd_printk(KERN_ERR "unable to register timer device (%i)\n", err);
1862 return 0;
1863}
1864
1865static void __exit alsa_timer_exit(void)
1866{
1867 struct list_head *p, *n;
1868
1869 snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0);
1870 /* unregister the system timer */
1871 list_for_each_safe(p, n, &snd_timer_list) {
1872 snd_timer_t *timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list);
1873 snd_timer_unregister(timer);
1874 }
1875 if (snd_timer_proc_entry) {
1876 snd_info_unregister(snd_timer_proc_entry);
1877 snd_timer_proc_entry = NULL;
1878 }
1879#ifdef SNDRV_OSS_INFO_DEV_TIMERS
1880 snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
1881#endif
1882}
1883
1884module_init(alsa_timer_init)
1885module_exit(alsa_timer_exit)
1886
1887EXPORT_SYMBOL(snd_timer_open);
1888EXPORT_SYMBOL(snd_timer_close);
1889EXPORT_SYMBOL(snd_timer_resolution);
1890EXPORT_SYMBOL(snd_timer_start);
1891EXPORT_SYMBOL(snd_timer_stop);
1892EXPORT_SYMBOL(snd_timer_continue);
1893EXPORT_SYMBOL(snd_timer_pause);
1894EXPORT_SYMBOL(snd_timer_new);
1895EXPORT_SYMBOL(snd_timer_notify);
1896EXPORT_SYMBOL(snd_timer_global_new);
1897EXPORT_SYMBOL(snd_timer_global_free);
1898EXPORT_SYMBOL(snd_timer_global_register);
1899EXPORT_SYMBOL(snd_timer_global_unregister);
1900EXPORT_SYMBOL(snd_timer_interrupt);
1901EXPORT_SYMBOL(snd_timer_system_resolution);
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
new file mode 100644
index 000000000000..9fbc3957a22d
--- /dev/null
+++ b/sound/core/timer_compat.c
@@ -0,0 +1,119 @@
1/*
2 * 32bit -> 64bit ioctl wrapper for timer API
3 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21/* This file included from timer.c */
22
23#include <linux/compat.h>
24
25struct sndrv_timer_info32 {
26 u32 flags;
27 s32 card;
28 unsigned char id[64];
29 unsigned char name[80];
30 u32 reserved0;
31 u32 resolution;
32 unsigned char reserved[64];
33};
34
35static int snd_timer_user_info_compat(struct file *file,
36 struct sndrv_timer_info32 __user *_info)
37{
38 snd_timer_user_t *tu;
39 struct sndrv_timer_info32 info;
40 snd_timer_t *t;
41
42 tu = file->private_data;
43 snd_assert(tu->timeri != NULL, return -ENXIO);
44 t = tu->timeri->timer;
45 snd_assert(t != NULL, return -ENXIO);
46 memset(&info, 0, sizeof(info));
47 info.card = t->card ? t->card->number : -1;
48 if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
49 info.flags |= SNDRV_TIMER_FLG_SLAVE;
50 strlcpy(info.id, t->id, sizeof(info.id));
51 strlcpy(info.name, t->name, sizeof(info.name));
52 info.resolution = t->hw.resolution;
53 if (copy_to_user(_info, &info, sizeof(*_info)))
54 return -EFAULT;
55 return 0;
56}
57
58struct sndrv_timer_status32 {
59 struct compat_timespec tstamp;
60 u32 resolution;
61 u32 lost;
62 u32 overrun;
63 u32 queue;
64 unsigned char reserved[64];
65};
66
67static int snd_timer_user_status_compat(struct file *file,
68 struct sndrv_timer_status32 __user *_status)
69{
70 snd_timer_user_t *tu;
71 snd_timer_status_t status;
72
73 tu = file->private_data;
74 snd_assert(tu->timeri != NULL, return -ENXIO);
75 memset(&status, 0, sizeof(status));
76 status.tstamp = tu->tstamp;
77 status.resolution = snd_timer_resolution(tu->timeri);
78 status.lost = tu->timeri->lost;
79 status.overrun = tu->overrun;
80 spin_lock_irq(&tu->qlock);
81 status.queue = tu->qused;
82 spin_unlock_irq(&tu->qlock);
83 if (copy_to_user(_status, &status, sizeof(status)))
84 return -EFAULT;
85 return 0;
86}
87
88/*
89 */
90
91enum {
92 SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct sndrv_timer_info32),
93 SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct sndrv_timer_status32),
94};
95
96static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
97{
98 void __user *argp = compat_ptr(arg);
99
100 switch (cmd) {
101 case SNDRV_TIMER_IOCTL_PVERSION:
102 case SNDRV_TIMER_IOCTL_TREAD:
103 case SNDRV_TIMER_IOCTL_GINFO:
104 case SNDRV_TIMER_IOCTL_GPARAMS:
105 case SNDRV_TIMER_IOCTL_GSTATUS:
106 case SNDRV_TIMER_IOCTL_SELECT:
107 case SNDRV_TIMER_IOCTL_PARAMS:
108 case SNDRV_TIMER_IOCTL_START:
109 case SNDRV_TIMER_IOCTL_STOP:
110 case SNDRV_TIMER_IOCTL_CONTINUE:
111 case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
112 return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
113 case SNDRV_TIMER_IOCTL_INFO32:
114 return snd_timer_user_info_compat(file, argp);
115 case SNDRV_TIMER_IOCTL_STATUS32:
116 return snd_timer_user_status_compat(file, argp);
117 }
118 return -ENOIOCTLCMD;
119}
diff --git a/sound/core/wrappers.c b/sound/core/wrappers.c
new file mode 100644
index 000000000000..9f393023c327
--- /dev/null
+++ b/sound/core/wrappers.c
@@ -0,0 +1,50 @@
1/*
2 * Various wrappers
3 * Copyright (c) by Jaroslav Kysela <perex@suse.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 <linux/config.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/ioport.h>
26#include <linux/vmalloc.h>
27#include <linux/fs.h>
28
29#ifdef CONFIG_SND_DEBUG_MEMORY
30void *snd_wrapper_kmalloc(size_t size, int flags)
31{
32 return kmalloc(size, flags);
33}
34
35void snd_wrapper_kfree(const void *obj)
36{
37 kfree(obj);
38}
39
40void *snd_wrapper_vmalloc(unsigned long size)
41{
42 return vmalloc(size);
43}
44
45void snd_wrapper_vfree(void *obj)
46{
47 vfree(obj);
48}
49#endif
50