blob: 701c7625c9713aafa310e742cf5e87dfa4dc3247 [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>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010019#include <linux/sched/signal.h>
20
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#define MIDIBUF_C
22
23#include "sound_config.h"
24
25
26/*
27 * Don't make MAX_QUEUE_SIZE larger than 4000
28 */
29
30#define MAX_QUEUE_SIZE 4000
31
32static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV];
33static wait_queue_head_t input_sleeper[MAX_MIDI_DEV];
34
35struct midi_buf
36{
37 int len, head, tail;
38 unsigned char queue[MAX_QUEUE_SIZE];
39};
40
41struct midi_parms
42{
43 long prech_timeout; /*
44 * Timeout before the first ch
45 */
46};
47
48static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
49static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
50static struct midi_parms parms[MAX_MIDI_DEV];
51
52static void midi_poll(unsigned long dummy);
53
54
Ingo Molnar8d06afa2005-09-09 13:10:40 -070055static DEFINE_TIMER(poll_timer, midi_poll, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static volatile int open_devs;
58static DEFINE_SPINLOCK(lock);
59
60#define DATA_AVAIL(q) (q->len)
61#define SPACE_AVAIL(q) (MAX_QUEUE_SIZE - q->len)
62
63#define QUEUE_BYTE(q, data) \
64 if (SPACE_AVAIL(q)) \
65 { \
66 unsigned long flags; \
67 spin_lock_irqsave(&lock, flags); \
68 q->queue[q->tail] = (data); \
69 q->len++; q->tail = (q->tail+1) % MAX_QUEUE_SIZE; \
70 spin_unlock_irqrestore(&lock, flags); \
71 }
72
73#define REMOVE_BYTE(q, data) \
74 if (DATA_AVAIL(q)) \
75 { \
76 unsigned long flags; \
77 spin_lock_irqsave(&lock, flags); \
78 data = q->queue[q->head]; \
79 q->len--; q->head = (q->head+1) % MAX_QUEUE_SIZE; \
80 spin_unlock_irqrestore(&lock, flags); \
81 }
82
83static void drain_midi_queue(int dev)
84{
85
86 /*
87 * Give the Midi driver time to drain its output queues
88 */
89
90 if (midi_devs[dev]->buffer_status != NULL)
Arnd Bergmann76439c22014-01-02 13:07:48 +010091 wait_event_interruptible_timeout(midi_sleeper[dev],
92 !midi_devs[dev]->buffer_status(dev), HZ/10);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94
95static void midi_input_intr(int dev, unsigned char data)
96{
97 if (midi_in_buf[dev] == NULL)
98 return;
99
100 if (data == 0xfe) /*
101 * Active sensing
102 */
103 return; /*
104 * Ignore
105 */
106
107 if (SPACE_AVAIL(midi_in_buf[dev])) {
108 QUEUE_BYTE(midi_in_buf[dev], data);
109 wake_up(&input_sleeper[dev]);
110 }
111}
112
113static void midi_output_intr(int dev)
114{
115 /*
116 * Currently NOP
117 */
118}
119
120static void midi_poll(unsigned long dummy)
121{
122 unsigned long flags;
123 int dev;
124
125 spin_lock_irqsave(&lock, flags);
126 if (open_devs)
127 {
128 for (dev = 0; dev < num_midis; dev++)
129 if (midi_devs[dev] != NULL && midi_out_buf[dev] != NULL)
130 {
Clemens Ladisch5e8e7c32009-08-10 10:05:23 +0200131 while (DATA_AVAIL(midi_out_buf[dev]))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 {
Clemens Ladisch5e8e7c32009-08-10 10:05:23 +0200133 int ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 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);
Clemens Ladisch5e8e7c32009-08-10 10:05:23 +0200139 if (!ok)
140 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 midi_out_buf[dev]->head = (midi_out_buf[dev]->head + 1) % MAX_QUEUE_SIZE;
142 midi_out_buf[dev]->len--;
143 }
144
145 if (DATA_AVAIL(midi_out_buf[dev]) < 100)
146 wake_up(&midi_sleeper[dev]);
147 }
148 poll_timer.expires = (1) + jiffies;
149 add_timer(&poll_timer);
150 /*
151 * Come back later
152 */
153 }
154 spin_unlock_irqrestore(&lock, flags);
155}
156
157int MIDIbuf_open(int dev, struct file *file)
158{
159 int mode, err;
160
161 dev = dev >> 4;
162 mode = translate_mode(file);
163
164 if (num_midis > MAX_MIDI_DEV)
165 {
166 printk(KERN_ERR "midi: Too many midi interfaces\n");
167 num_midis = MAX_MIDI_DEV;
168 }
169 if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
170 return -ENXIO;
171 /*
172 * Interrupts disabled. Be careful
173 */
174
175 module_put(midi_devs[dev]->owner);
176
177 if ((err = midi_devs[dev]->open(dev, mode,
178 midi_input_intr, midi_output_intr)) < 0)
179 return err;
180
181 parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT;
Jesper Juhlea7dd252010-11-09 00:11:03 +0100182 midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184 if (midi_in_buf[dev] == NULL)
185 {
186 printk(KERN_WARNING "midi: Can't allocate buffer\n");
187 midi_devs[dev]->close(dev);
188 return -EIO;
189 }
190 midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0;
191
Jesper Juhlea7dd252010-11-09 00:11:03 +0100192 midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
194 if (midi_out_buf[dev] == NULL)
195 {
196 printk(KERN_WARNING "midi: Can't allocate buffer\n");
197 midi_devs[dev]->close(dev);
198 vfree(midi_in_buf[dev]);
199 midi_in_buf[dev] = NULL;
200 return -EIO;
201 }
202 midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0;
203 open_devs++;
204
205 init_waitqueue_head(&midi_sleeper[dev]);
206 init_waitqueue_head(&input_sleeper[dev]);
207
208 if (open_devs < 2) /* This was first open */
209 {
210 poll_timer.expires = 1 + jiffies;
211 add_timer(&poll_timer); /* Start polling */
212 }
213 return err;
214}
215
216void MIDIbuf_release(int dev, struct file *file)
217{
218 int mode;
219
220 dev = dev >> 4;
221 mode = translate_mode(file);
222
223 if (dev < 0 || dev >= num_midis || midi_devs[dev] == NULL)
224 return;
225
226 /*
227 * Wait until the queue is empty
228 */
229
230 if (mode != OPEN_READ)
231 {
232 midi_devs[dev]->outputc(dev, 0xfe); /*
233 * Active sensing to shut the
234 * devices
235 */
236
Arnd Bergmann76439c22014-01-02 13:07:48 +0100237 wait_event_interruptible(midi_sleeper[dev],
238 !DATA_AVAIL(midi_out_buf[dev]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 /*
240 * Sync
241 */
242
243 drain_midi_queue(dev); /*
244 * Ensure the output queues are empty
245 */
246 }
247
248 midi_devs[dev]->close(dev);
249
250 open_devs--;
251 if (open_devs == 0)
252 del_timer_sync(&poll_timer);
253 vfree(midi_in_buf[dev]);
254 vfree(midi_out_buf[dev]);
255 midi_in_buf[dev] = NULL;
256 midi_out_buf[dev] = NULL;
257
258 module_put(midi_devs[dev]->owner);
259}
260
261int MIDIbuf_write(int dev, struct file *file, const char __user *buf, int count)
262{
263 int c, n, i;
264 unsigned char tmp_data;
265
266 dev = dev >> 4;
267
268 if (!count)
269 return 0;
270
271 c = 0;
272
273 while (c < count)
274 {
275 n = SPACE_AVAIL(midi_out_buf[dev]);
276
277 if (n == 0) { /*
278 * No space just now.
279 */
280
281 if (file->f_flags & O_NONBLOCK) {
282 c = -EAGAIN;
283 goto out;
284 }
285
Arnd Bergmann76439c22014-01-02 13:07:48 +0100286 if (wait_event_interruptible(midi_sleeper[dev],
287 SPACE_AVAIL(midi_out_buf[dev])))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 {
289 c = -EINTR;
290 goto out;
291 }
292 n = SPACE_AVAIL(midi_out_buf[dev]);
293 }
294 if (n > (count - c))
295 n = count - c;
296
297 for (i = 0; i < n; i++)
298 {
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300299 /* BROKE BROKE BROKE - CAN'T DO THIS WITH CLI !! */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 /* yes, think the same, so I removed the cli() brackets
301 QUEUE_BYTE is protected against interrupts */
302 if (copy_from_user((char *) &tmp_data, &(buf)[c], 1)) {
303 c = -EFAULT;
304 goto out;
305 }
306 QUEUE_BYTE(midi_out_buf[dev], tmp_data);
307 c++;
308 }
309 }
310out:
311 return c;
312}
313
314
315int MIDIbuf_read(int dev, struct file *file, char __user *buf, int count)
316{
317 int n, c = 0;
318 unsigned char tmp_data;
319
320 dev = dev >> 4;
321
322 if (!DATA_AVAIL(midi_in_buf[dev])) { /*
323 * No data yet, wait
324 */
325 if (file->f_flags & O_NONBLOCK) {
326 c = -EAGAIN;
327 goto out;
328 }
Arnd Bergmann76439c22014-01-02 13:07:48 +0100329 wait_event_interruptible_timeout(input_sleeper[dev],
330 DATA_AVAIL(midi_in_buf[dev]),
331 parms[dev].prech_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 if (signal_pending(current))
334 c = -EINTR; /* The user is getting restless */
335 }
336 if (c == 0 && DATA_AVAIL(midi_in_buf[dev])) /*
337 * Got some bytes
338 */
339 {
340 n = DATA_AVAIL(midi_in_buf[dev]);
341 if (n > count)
342 n = count;
343 c = 0;
344
345 while (c < n)
346 {
347 char *fixit;
348 REMOVE_BYTE(midi_in_buf[dev], tmp_data);
349 fixit = (char *) &tmp_data;
350 /* BROKE BROKE BROKE */
351 /* yes removed the cli() brackets again
352 should q->len,tail&head be atomic_t? */
353 if (copy_to_user(&(buf)[c], fixit, 1)) {
354 c = -EFAULT;
355 goto out;
356 }
357 c++;
358 }
359 }
360out:
361 return c;
362}
363
364int MIDIbuf_ioctl(int dev, struct file *file,
365 unsigned int cmd, void __user *arg)
366{
367 int val;
368
369 dev = dev >> 4;
370
371 if (((cmd >> 8) & 0xff) == 'C')
372 {
373 if (midi_devs[dev]->coproc) /* Coprocessor ioctl */
374 return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
375/* printk("/dev/midi%d: No coprocessor for this device\n", dev);*/
376 return -ENXIO;
377 }
378 else
379 {
380 switch (cmd)
381 {
382 case SNDCTL_MIDI_PRETIME:
383 if (get_user(val, (int __user *)arg))
384 return -EFAULT;
385 if (val < 0)
386 val = 0;
387 val = (HZ * val) / 10;
388 parms[dev].prech_timeout = val;
389 return put_user(val, (int __user *)arg);
390
391 default:
392 if (!midi_devs[dev]->ioctl)
393 return -EINVAL;
394 return midi_devs[dev]->ioctl(dev, cmd, arg);
395 }
396 }
397}
398
399/* No kernel lock - fine */
400unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
401{
402 unsigned int mask = 0;
403
404 dev = dev >> 4;
405
406 /* input */
407 poll_wait(file, &input_sleeper[dev], wait);
408 if (DATA_AVAIL(midi_in_buf[dev]))
409 mask |= POLLIN | POLLRDNORM;
410
411 /* output */
412 poll_wait(file, &midi_sleeper[dev], wait);
413 if (!SPACE_AVAIL(midi_out_buf[dev]))
414 mask |= POLLOUT | POLLWRNORM;
415
416 return mask;
417}
418
419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420int MIDIbuf_avail(int dev)
421{
422 if (midi_in_buf[dev])
423 return DATA_AVAIL (midi_in_buf[dev]);
424 return 0;
425}
Adrian Bunkece7f772006-10-04 02:17:31 -0700426EXPORT_SYMBOL(MIDIbuf_avail);
427