Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/oss/midibuf.c
10814 views
1
/*
2
* sound/oss/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
30
static wait_queue_head_t midi_sleeper[MAX_MIDI_DEV];
31
static wait_queue_head_t input_sleeper[MAX_MIDI_DEV];
32
33
struct midi_buf
34
{
35
int len, head, tail;
36
unsigned char queue[MAX_QUEUE_SIZE];
37
};
38
39
struct midi_parms
40
{
41
long prech_timeout; /*
42
* Timeout before the first ch
43
*/
44
};
45
46
static struct midi_buf *midi_out_buf[MAX_MIDI_DEV] = {NULL};
47
static struct midi_buf *midi_in_buf[MAX_MIDI_DEV] = {NULL};
48
static struct midi_parms parms[MAX_MIDI_DEV];
49
50
static void midi_poll(unsigned long dummy);
51
52
53
static DEFINE_TIMER(poll_timer, midi_poll, 0, 0);
54
55
static volatile int open_devs;
56
static 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
81
static 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
94
static 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
112
static void midi_output_intr(int dev)
113
{
114
/*
115
* Currently NOP
116
*/
117
}
118
119
static 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
while (DATA_AVAIL(midi_out_buf[dev]))
131
{
132
int ok;
133
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);
138
if (!ok)
139
break;
140
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
156
int 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;
181
midi_in_buf[dev] = vmalloc(sizeof(struct midi_buf));
182
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
191
midi_out_buf[dev] = vmalloc(sizeof(struct midi_buf));
192
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
215
void 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
260
int 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 - CAN'T 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
}
309
out:
310
return c;
311
}
312
313
314
int 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
}
358
out:
359
return c;
360
}
361
362
int 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 */
398
unsigned 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
418
int MIDIbuf_avail(int dev)
419
{
420
if (midi_in_buf[dev])
421
return DATA_AVAIL (midi_in_buf[dev]);
422
return 0;
423
}
424
EXPORT_SYMBOL(MIDIbuf_avail);
425
426
427