aboutsummaryrefslogtreecommitdiffstats
path: root/sound/oss/midibuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/oss/midibuf.c')
-rw-r--r--sound/oss/midibuf.c431
1 files changed, 431 insertions, 0 deletions
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
new file mode 100644
index 000000000000..b2676fa34630
--- /dev/null
+++ b/sound/oss/midibuf.c
@@ -0,0 +1,431 @@
1/*
2 * sound/midibuf.c
3 *
4 * Device file manager for /dev/midi#
5 */
6/*
7 * Copyright (C) by Hannu Savolainen 1993-1997
8 *
9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10 * Version 2 (June 1991). See the "COPYING" file distributed with this software
11 * for more info.
12 */
13/*
14 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
15 */
16#include <linux/stddef.h>
17#include <linux/kmod.h>
18#include <linux/spinlock.h>
19#define MIDIBUF_C
20
21#include "sound_config.h"
22
23
24/*
25 * Don't make MAX_QUEUE_SIZE larger than 4000
26 */
27
28#define MAX_QUEUE_SIZE 4000
29
30static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV];
31static wait_queue_head_t input_sleeper[MAX_MIDI_DEV];
32
33struct midi_buf
34{
35 int len, head, tail;
36 unsigned char queue[MAX_QUEUE_SIZE];
37};
38
39struct midi_parms
40{
41 long prech_timeout; /*
42 * Timeout before the first ch
43 */
44};
45
46static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
47static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
48static struct midi_parms parms[MAX_MIDI_DEV];
49
50static void midi_poll(unsigned long dummy);
51
52
53static struct timer_list poll_timer = TIMER_INITIALIZER(midi_poll, 0, 0);
54
55static volatile int open_devs;
56static DEFINE_SPINLOCK(lock);
57
58#define DATA_AVAIL(q) (q->len)
59#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
60
61#define QUEUE_BYTE(q, data) \
62 if (SPACE_AVAIL(q)) \
63 { \
64 unsigned long flags; \
65 spin_lock_irqsave(&lock, flags); \
66 q->queue[q->tail] = (data); \
67 q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
68 spin_unlock_irqrestore(&lock, flags); \
69 }
70
71#define REMOVE_BYTE(q, data) \
72 if (DATA_AVAIL(q)) \
73 { \
74 unsigned long flags; \
75 spin_lock_irqsave(&lock, flags); \
76 data = q->queue[q->head]; \
77 q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
78 spin_unlock_irqrestore(&lock, flags); \
79 }
80
81static void drain_midi_queue(int dev)
82{
83
84 /*
85 * Give the Midi driver time to drain its output queues
86 */
87
88 if (midi_devs[dev]->buffer_status != NULL)
89 while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev))
90 interruptible_sleep_on_timeout(&midi_sleeper[dev],
91 HZ/10);
92}
93
94static void midi_input_intr(int dev, unsigned char data)
95{
96 if (midi_in_buf[dev] == NULL)
97 return;
98
99 if (data == 0xfe) /*
100 * Active sensing
101 */
102 return; /*
103 * Ignore
104 */
105
106 if (SPACE_AVAIL(midi_in_buf[dev])) {
107 QUEUE_BYTE(midi_in_buf[dev], data);
108 wake_up(&input_sleeper[dev]);
109 }
110}
111
112static void midi_output_intr(int dev)
113{
114 /*
115 * Currently NOP
116 */
117}
118
119static void midi_poll(unsigned long dummy)
120{
121 unsigned long flags;
122 int dev;
123
124 spin_lock_irqsave(&lock, flags);
125 if (open_devs)
126 {
127 for (dev = 0; dev < num_midis; dev++)
128 if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
129 {
130 int ok = 1;
131
132 while (DATA_AVAIL(midi_out_buf[dev]) && ok)
133 {
134 int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
135
136 spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
137 ok = midi_devs[dev]->outputc(dev, c);
138 spin_lock_irqsave(&lock, flags);
139 midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
140 midi_out_buf[dev]->len--;
141 }
142
143 if (DATA_AVAIL(midi_out_buf[dev]) < 100)
144 wake_up(&midi_sleeper[dev]);
145 }
146 poll_timer.expires = (1) + jiffies;
147 add_timer(&poll_timer);
148 /*
149 * Come back later
150 */
151 }
152 spin_unlock_irqrestore(&lock, flags);
153}
154
155int MIDIbuf_open(int dev, struct file *file)
156{
157 int mode, err;
158
159 dev = dev >> 4;
160 mode = translate_mode(file);
161
162 if (num_midis > MAX_MIDI_DEV)
163 {
164 printk(KERN_ERR "midi: Too many midi interfaces\n");
165 num_midis = MAX_MIDI_DEV;
166 }
167 if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
168 return -ENXIO;
169 /*
170 * Interrupts disabled. Be careful
171 */
172
173 module_put(midi_devs[dev]->owner);
174
175 if ((err = midi_devs[dev]->open(dev, mode,
176 midi_input_intr, midi_output_intr)) < 0)
177 return err;
178
179 parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
180 midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
181
182 if (midi_in_buf[dev] == NULL)
183 {
184 printk(KERN_WARNING "midi: Can't allocate buffer\n");
185 midi_devs[dev]->close(dev);
186 return -EIO;
187 }
188 midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
189
190 midi_out_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf));
191
192 if (midi_out_buf[dev] == NULL)
193 {
194 printk(KERN_WARNING "midi: Can't allocate buffer\n");
195 midi_devs[dev]->close(dev);
196 vfree(midi_in_buf[dev]);
197 midi_in_buf[dev] = NULL;
198 return -EIO;
199 }
200 midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
201 open_devs++;
202
203 init_waitqueue_head(&midi_sleeper[dev]);
204 init_waitqueue_head(&input_sleeper[dev]);
205
206 if (open_devs < 2) /* This was first open */
207 {
208 poll_timer.expires = 1 + jiffies;
209 add_timer(&poll_timer); /* Start polling */
210 }
211 return err;
212}
213
214void MIDIbuf_release(int dev, struct file *file)
215{
216 int mode;
217
218 dev = dev >> 4;
219 mode = translate_mode(file);
220
221 if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
222 return;
223
224 /*
225 * Wait until the queue is empty
226 */
227
228 if (mode != OPEN_READ)
229 {
230 midi_devs[dev]->outputc(dev, 0xfe); /*
231 * Active sensing to shut the
232 * devices
233 */
234
235 while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev]))
236 interruptible_sleep_on(&midi_sleeper[dev]);
237 /*
238 * Sync
239 */
240
241 drain_midi_queue(dev); /*
242 * Ensure the output queues are empty
243 */
244 }
245
246 midi_devs[dev]->close(dev);
247
248 open_devs--;
249 if (open_devs == 0)
250 del_timer_sync(&poll_timer);
251 vfree(midi_in_buf[dev]);
252 vfree(midi_out_buf[dev]);
253 midi_in_buf[dev] = NULL;
254 midi_out_buf[dev] = NULL;
255
256 module_put(midi_devs[dev]->owner);
257}
258
259int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
260{
261 int c, n, i;
262 unsigned char tmp_data;
263
264 dev = dev >> 4;
265
266 if (!count)
267 return 0;
268
269 c = 0;
270
271 while (c < count)
272 {
273 n = SPACE_AVAIL(midi_out_buf[dev]);
274
275 if (n == 0) { /*
276 * No space just now.
277 */
278
279 if (file->f_flags & O_NONBLOCK) {
280 c = -EAGAIN;
281 goto out;
282 }
283
284 interruptible_sleep_on(&midi_sleeper[dev]);
285 if (signal_pending(current))
286 {
287 c = -EINTR;
288 goto out;
289 }
290 n = SPACE_AVAIL(midi_out_buf[dev]);
291 }
292 if (n > (count - c))
293 n = count - c;
294
295 for (i = 0; i < n; i++)
296 {
297 /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */
298 /* yes, think the same, so I removed the cli() brackets
299 QUEUE_BYTE is protected against interrupts */
300 if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
301 c = -EFAULT;
302 goto out;
303 }
304 QUEUE_BYTE(midi_out_buf[dev], tmp_data);
305 c++;
306 }
307 }
308out:
309 return c;
310}
311
312
313int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
314{
315 int n, c = 0;
316 unsigned char tmp_data;
317
318 dev = dev >> 4;
319
320 if (!DATA_AVAIL(midi_in_buf[dev])) { /*
321 * No data yet, wait
322 */
323 if (file->f_flags & O_NONBLOCK) {
324 c = -EAGAIN;
325 goto out;
326 }
327 interruptible_sleep_on_timeout(&input_sleeper[dev],
328 parms[dev].prech_timeout);
329
330 if (signal_pending(current))
331 c = -EINTR; /* The user is getting restless */
332 }
333 if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /*
334 * Got some bytes
335 */
336 {
337 n = DATA_AVAIL(midi_in_buf[dev]);
338 if (n > count)
339 n = count;
340 c = 0;
341
342 while (c < n)
343 {
344 char *fixit;
345 REMOVE_BYTE(midi_in_buf[dev], tmp_data);
346 fixit = (char *) &tmp_data;
347 /* BROKE BROKE BROKE */
348 /* yes removed the cli() brackets again
349 should q->len,tail&head be atomic_t? */
350 if (copy_to_user(&(buf)[c], fixit, 1)) {
351 c = -EFAULT;
352 goto out;
353 }
354 c++;
355 }
356 }
357out:
358 return c;
359}
360
361int MIDIbuf_ioctl(int dev, struct file *file,
362 unsigned int cmd, void __user *arg)
363{
364 int val;
365
366 dev = dev >> 4;
367
368 if (((cmd >> 8) & 0xff) == 'C')
369 {
370 if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
371 return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
372/* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
373 return -ENXIO;
374 }
375 else
376 {
377 switch (cmd)
378 {
379 case SNDCTL_MIDI_PRETIME:
380 if (get_user(val, (int __user *)arg))
381 return -EFAULT;
382 if (val < 0)
383 val = 0;
384 val = (HZ * val) / 10;
385 parms[dev].prech_timeout = val;
386 return put_user(val, (int __user *)arg);
387
388 default:
389 if (!midi_devs[dev]->ioctl)
390 return -EINVAL;
391 return midi_devs[dev]->ioctl(dev, cmd, arg);
392 }
393 }
394}
395
396/* No kernel lock - fine */
397unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
398{
399 unsigned int mask = 0;
400
401 dev = dev >> 4;
402
403 /* input */
404 poll_wait(file, &input_sleeper[dev], wait);
405 if (DATA_AVAIL(midi_in_buf[dev]))
406 mask |= POLLIN | POLLRDNORM;
407
408 /* output */
409 poll_wait(file, &midi_sleeper[dev], wait);
410 if (!SPACE_AVAIL(midi_out_buf[dev]))
411 mask |= POLLOUT | POLLWRNORM;
412
413 return mask;
414}
415
416
417void MIDIbuf_init(void)
418{
419 /* drag in midi_syms.o */
420 {
421 extern char midi_syms_symbol;
422 midi_syms_symbol = 0;
423 }
424}
425
426int MIDIbuf_avail(int dev)
427{
428 if (midi_in_buf[dev])
429 return DATA_AVAIL (midi_in_buf[dev]);
430 return 0;
431}