blob: ceedb1eff203812e85049f7cdb46b92a588fc557 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Uwe Zeisbergerf30c2262006-10-03 23:01:26 +02002 * sound/oss/midibuf.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
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
Ingo Molnar8d06afa2005-09-09 13:10:40 -070053static DEFINE_TIMER(poll_timer, midi_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
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 {
Clemens Ladisch5e8e7c32009-08-10 10:05:23 +0200130 while (DATA_AVAIL(midi_out_buf[dev]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 {
Clemens Ladisch5e8e7c32009-08-10 10:05:23 +0200132 int ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 int c = midi_out_buf[dev]->queue[midi_out_buf[dev]->head];
134
135 spin_unlock_irqrestore(&lock,flags);/* Give some time to others */
136 ok = midi_devs[dev]->outputc(dev, c);
137 spin_lock_irqsave(&lock, flags);
Clemens Ladisch5e8e7c32009-08-10 10:05:23 +0200138 if (!ok)
139 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
141 midi_out_buf[dev]->len--;
142 }
143
144 if (DATA_AVAIL(midi_out_buf[dev]) < 100)
145 wake_up(&midi_sleeper[dev]);
146 }
147 poll_timer.expires = (1) + jiffies;
148 add_timer(&poll_timer);
149 /*
150 * Come back later
151 */
152 }
153 spin_unlock_irqrestore(&lock, flags);
154}
155
156int MIDIbuf_open(int dev, struct file *file)
157{
158 int mode, err;
159
160 dev = dev >> 4;
161 mode = translate_mode(file);
162
163 if (num_midis > MAX_MIDI_DEV)
164 {
165 printk(KERN_ERR "midi: Too many midi interfaces\n");
166 num_midis = MAX_MIDI_DEV;
167 }
168 if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
169 return -ENXIO;
170 /*
171 * Interrupts disabled. Be careful
172 */
173
174 module_put(midi_devs[dev]->owner);
175
176 if ((err = midi_devs[dev]->open(dev, mode,
177 midi_input_intr, midi_output_intr)) < 0)
178 return err;
179
180 parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
Jesper Juhlea7dd252010-11-09 00:11:03 +0100181 midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 if (midi_in_buf[dev] == NULL)
184 {
185 printk(KERN_WARNING "midi: Can't allocate buffer\n");
186 midi_devs[dev]->close(dev);
187 return -EIO;
188 }
189 midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
190
Jesper Juhlea7dd252010-11-09 00:11:03 +0100191 midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193 if (midi_out_buf[dev] == NULL)
194 {
195 printk(KERN_WARNING "midi: Can't allocate buffer\n");
196 midi_devs[dev]->close(dev);
197 vfree(midi_in_buf[dev]);
198 midi_in_buf[dev] = NULL;
199 return -EIO;
200 }
201 midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
202 open_devs++;
203
204 init_waitqueue_head(&midi_sleeper[dev]);
205 init_waitqueue_head(&input_sleeper[dev]);
206
207 if (open_devs < 2) /* This was first open */
208 {
209 poll_timer.expires = 1 + jiffies;
210 add_timer(&poll_timer); /* Start polling */
211 }
212 return err;
213}
214
215void MIDIbuf_release(int dev, struct file *file)
216{
217 int mode;
218
219 dev = dev >> 4;
220 mode = translate_mode(file);
221
222 if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
223 return;
224
225 /*
226 * Wait until the queue is empty
227 */
228
229 if (mode != OPEN_READ)
230 {
231 midi_devs[dev]->outputc(dev, 0xfe); /*
232 * Active sensing to shut the
233 * devices
234 */
235
236 while (!signal_pending(current) && DATA_AVAIL(midi_out_buf[dev]))
237 interruptible_sleep_on(&midi_sleeper[dev]);
238 /*
239 * Sync
240 */
241
242 drain_midi_queue(dev); /*
243 * Ensure the output queues are empty
244 */
245 }
246
247 midi_devs[dev]->close(dev);
248
249 open_devs--;
250 if (open_devs == 0)
251 del_timer_sync(&poll_timer);
252 vfree(midi_in_buf[dev]);
253 vfree(midi_out_buf[dev]);
254 midi_in_buf[dev] = NULL;
255 midi_out_buf[dev] = NULL;
256
257 module_put(midi_devs[dev]->owner);
258}
259
260int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
261{
262 int c, n, i;
263 unsigned char tmp_data;
264
265 dev = dev >> 4;
266
267 if (!count)
268 return 0;
269
270 c = 0;
271
272 while (c < count)
273 {
274 n = SPACE_AVAIL(midi_out_buf[dev]);
275
276 if (n == 0) { /*
277 * No space just now.
278 */
279
280 if (file->f_flags & O_NONBLOCK) {
281 c = -EAGAIN;
282 goto out;
283 }
284
285 interruptible_sleep_on(&midi_sleeper[dev]);
286 if (signal_pending(current))
287 {
288 c = -EINTR;
289 goto out;
290 }
291 n = SPACE_AVAIL(midi_out_buf[dev]);
292 }
293 if (n > (count - c))
294 n = count - c;
295
296 for (i = 0; i < n; i++)
297 {
298 /* BROKE BROKE BROKE - CANT DO THIS WITH CLI !! */
299 /* yes, think the same, so I removed the cli() brackets
300 QUEUE_BYTE is protected against interrupts */
301 if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
302 c = -EFAULT;
303 goto out;
304 }
305 QUEUE_BYTE(midi_out_buf[dev], tmp_data);
306 c++;
307 }
308 }
309out:
310 return c;
311}
312
313
314int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
315{
316 int n, c = 0;
317 unsigned char tmp_data;
318
319 dev = dev >> 4;
320
321 if (!DATA_AVAIL(midi_in_buf[dev])) { /*
322 * No data yet, wait
323 */
324 if (file->f_flags & O_NONBLOCK) {
325 c = -EAGAIN;
326 goto out;
327 }
328 interruptible_sleep_on_timeout(&input_sleeper[dev],
329 parms[dev].prech_timeout);
330
331 if (signal_pending(current))
332 c = -EINTR; /* The user is getting restless */
333 }
334 if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /*
335 * Got some bytes
336 */
337 {
338 n = DATA_AVAIL(midi_in_buf[dev]);
339 if (n > count)
340 n = count;
341 c = 0;
342
343 while (c < n)
344 {
345 char *fixit;
346 REMOVE_BYTE(midi_in_buf[dev], tmp_data);
347 fixit = (char *) &tmp_data;
348 /* BROKE BROKE BROKE */
349 /* yes removed the cli() brackets again
350 should q->len,tail&head be atomic_t? */
351 if (copy_to_user(&(buf)[c], fixit, 1)) {
352 c = -EFAULT;
353 goto out;
354 }
355 c++;
356 }
357 }
358out:
359 return c;
360}
361
362int MIDIbuf_ioctl(int dev, struct file *file,
363 unsigned int cmd, void __user *arg)
364{
365 int val;
366
367 dev = dev >> 4;
368
369 if (((cmd >> 8) & 0xff) == 'C')
370 {
371 if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
372 return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
373/* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
374 return -ENXIO;
375 }
376 else
377 {
378 switch (cmd)
379 {
380 case SNDCTL_MIDI_PRETIME:
381 if (get_user(val, (int __user *)arg))
382 return -EFAULT;
383 if (val < 0)
384 val = 0;
385 val = (HZ * val) / 10;
386 parms[dev].prech_timeout = val;
387 return put_user(val, (int __user *)arg);
388
389 default:
390 if (!midi_devs[dev]->ioctl)
391 return -EINVAL;
392 return midi_devs[dev]->ioctl(dev, cmd, arg);
393 }
394 }
395}
396
397/* No kernel lock - fine */
398unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
399{
400 unsigned int mask = 0;
401
402 dev = dev >> 4;
403
404 /* input */
405 poll_wait(file, &input_sleeper[dev], wait);
406 if (DATA_AVAIL(midi_in_buf[dev]))
407 mask |= POLLIN | POLLRDNORM;
408
409 /* output */
410 poll_wait(file, &midi_sleeper[dev], wait);
411 if (!SPACE_AVAIL(midi_out_buf[dev]))
412 mask |= POLLOUT | POLLWRNORM;
413
414 return mask;
415}
416
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418int MIDIbuf_avail(int dev)
419{
420 if (midi_in_buf[dev])
421 return DATA_AVAIL (midi_in_buf[dev]);
422 return 0;
423}
Adrian Bunkece7f772006-10-04 02:17:31 -0700424EXPORT_SYMBOL(MIDIbuf_avail);
425