Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/core/seq/seq_midi.c
10820 views
1
/*
2
* Generic MIDI synth driver for ALSA sequencer
3
* Copyright (c) 1998 by Frank van de Pol <[email protected]>
4
* Jaroslav Kysela <[email protected]>
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
Possible 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 <linux/init.h>
30
#include <linux/slab.h>
31
#include <linux/errno.h>
32
#include <linux/string.h>
33
#include <linux/moduleparam.h>
34
#include <linux/mutex.h>
35
#include <sound/core.h>
36
#include <sound/rawmidi.h>
37
#include <sound/seq_kernel.h>
38
#include <sound/seq_device.h>
39
#include <sound/seq_midi_event.h>
40
#include <sound/initval.h>
41
42
MODULE_AUTHOR("Frank van de Pol <[email protected]>, Jaroslav Kysela <[email protected]>");
43
MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth.");
44
MODULE_LICENSE("GPL");
45
static int output_buffer_size = PAGE_SIZE;
46
module_param(output_buffer_size, int, 0644);
47
MODULE_PARM_DESC(output_buffer_size, "Output buffer size in bytes.");
48
static int input_buffer_size = PAGE_SIZE;
49
module_param(input_buffer_size, int, 0644);
50
MODULE_PARM_DESC(input_buffer_size, "Input buffer size in bytes.");
51
52
/* data for this midi synth driver */
53
struct seq_midisynth {
54
struct snd_card *card;
55
int device;
56
int subdevice;
57
struct snd_rawmidi_file input_rfile;
58
struct snd_rawmidi_file output_rfile;
59
int seq_client;
60
int seq_port;
61
struct snd_midi_event *parser;
62
};
63
64
struct seq_midisynth_client {
65
int seq_client;
66
int num_ports;
67
int ports_per_device[SNDRV_RAWMIDI_DEVICES];
68
struct seq_midisynth *ports[SNDRV_RAWMIDI_DEVICES];
69
};
70
71
static struct seq_midisynth_client *synths[SNDRV_CARDS];
72
static DEFINE_MUTEX(register_mutex);
73
74
/* handle rawmidi input event (MIDI v1.0 stream) */
75
static void snd_midi_input_event(struct snd_rawmidi_substream *substream)
76
{
77
struct snd_rawmidi_runtime *runtime;
78
struct seq_midisynth *msynth;
79
struct snd_seq_event ev;
80
char buf[16], *pbuf;
81
long res, count;
82
83
if (substream == NULL)
84
return;
85
runtime = substream->runtime;
86
msynth = runtime->private_data;
87
if (msynth == NULL)
88
return;
89
memset(&ev, 0, sizeof(ev));
90
while (runtime->avail > 0) {
91
res = snd_rawmidi_kernel_read(substream, buf, sizeof(buf));
92
if (res <= 0)
93
continue;
94
if (msynth->parser == NULL)
95
continue;
96
pbuf = buf;
97
while (res > 0) {
98
count = snd_midi_event_encode(msynth->parser, pbuf, res, &ev);
99
if (count < 0)
100
break;
101
pbuf += count;
102
res -= count;
103
if (ev.type != SNDRV_SEQ_EVENT_NONE) {
104
ev.source.port = msynth->seq_port;
105
ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
106
snd_seq_kernel_client_dispatch(msynth->seq_client, &ev, 1, 0);
107
/* clear event and reset header */
108
memset(&ev, 0, sizeof(ev));
109
}
110
}
111
}
112
}
113
114
static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, int count)
115
{
116
struct snd_rawmidi_runtime *runtime;
117
int tmp;
118
119
if (snd_BUG_ON(!substream || !buf))
120
return -EINVAL;
121
runtime = substream->runtime;
122
if ((tmp = runtime->avail) < count) {
123
if (printk_ratelimit())
124
snd_printk(KERN_ERR "MIDI output buffer overrun\n");
125
return -ENOMEM;
126
}
127
if (snd_rawmidi_kernel_write(substream, buf, count) < count)
128
return -EINVAL;
129
return 0;
130
}
131
132
static int event_process_midi(struct snd_seq_event *ev, int direct,
133
void *private_data, int atomic, int hop)
134
{
135
struct seq_midisynth *msynth = private_data;
136
unsigned char msg[10]; /* buffer for constructing midi messages */
137
struct snd_rawmidi_substream *substream;
138
int len;
139
140
if (snd_BUG_ON(!msynth))
141
return -EINVAL;
142
substream = msynth->output_rfile.output;
143
if (substream == NULL)
144
return -ENODEV;
145
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) { /* special case, to save space */
146
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE) {
147
/* invalid event */
148
snd_printd("seq_midi: invalid sysex event flags = 0x%x\n", ev->flags);
149
return 0;
150
}
151
snd_seq_dump_var_event(ev, (snd_seq_dump_func_t)dump_midi, substream);
152
snd_midi_event_reset_decode(msynth->parser);
153
} else {
154
if (msynth->parser == NULL)
155
return -EIO;
156
len = snd_midi_event_decode(msynth->parser, msg, sizeof(msg), ev);
157
if (len < 0)
158
return 0;
159
if (dump_midi(substream, msg, len) < 0)
160
snd_midi_event_reset_decode(msynth->parser);
161
}
162
return 0;
163
}
164
165
166
static int snd_seq_midisynth_new(struct seq_midisynth *msynth,
167
struct snd_card *card,
168
int device,
169
int subdevice)
170
{
171
if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &msynth->parser) < 0)
172
return -ENOMEM;
173
msynth->card = card;
174
msynth->device = device;
175
msynth->subdevice = subdevice;
176
return 0;
177
}
178
179
/* open associated midi device for input */
180
static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe *info)
181
{
182
int err;
183
struct seq_midisynth *msynth = private_data;
184
struct snd_rawmidi_runtime *runtime;
185
struct snd_rawmidi_params params;
186
187
/* open midi port */
188
if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
189
msynth->subdevice,
190
SNDRV_RAWMIDI_LFLG_INPUT,
191
&msynth->input_rfile)) < 0) {
192
snd_printd("midi input open failed!!!\n");
193
return err;
194
}
195
runtime = msynth->input_rfile.input->runtime;
196
memset(&params, 0, sizeof(params));
197
params.avail_min = 1;
198
params.buffer_size = input_buffer_size;
199
if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, &params)) < 0) {
200
snd_rawmidi_kernel_release(&msynth->input_rfile);
201
return err;
202
}
203
snd_midi_event_reset_encode(msynth->parser);
204
runtime->event = snd_midi_input_event;
205
runtime->private_data = msynth;
206
snd_rawmidi_kernel_read(msynth->input_rfile.input, NULL, 0);
207
return 0;
208
}
209
210
/* close associated midi device for input */
211
static int midisynth_unsubscribe(void *private_data, struct snd_seq_port_subscribe *info)
212
{
213
int err;
214
struct seq_midisynth *msynth = private_data;
215
216
if (snd_BUG_ON(!msynth->input_rfile.input))
217
return -EINVAL;
218
err = snd_rawmidi_kernel_release(&msynth->input_rfile);
219
return err;
220
}
221
222
/* open associated midi device for output */
223
static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info)
224
{
225
int err;
226
struct seq_midisynth *msynth = private_data;
227
struct snd_rawmidi_params params;
228
229
/* open midi port */
230
if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
231
msynth->subdevice,
232
SNDRV_RAWMIDI_LFLG_OUTPUT,
233
&msynth->output_rfile)) < 0) {
234
snd_printd("midi output open failed!!!\n");
235
return err;
236
}
237
memset(&params, 0, sizeof(params));
238
params.avail_min = 1;
239
params.buffer_size = output_buffer_size;
240
params.no_active_sensing = 1;
241
if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, &params)) < 0) {
242
snd_rawmidi_kernel_release(&msynth->output_rfile);
243
return err;
244
}
245
snd_midi_event_reset_decode(msynth->parser);
246
return 0;
247
}
248
249
/* close associated midi device for output */
250
static int midisynth_unuse(void *private_data, struct snd_seq_port_subscribe *info)
251
{
252
struct seq_midisynth *msynth = private_data;
253
254
if (snd_BUG_ON(!msynth->output_rfile.output))
255
return -EINVAL;
256
snd_rawmidi_drain_output(msynth->output_rfile.output);
257
return snd_rawmidi_kernel_release(&msynth->output_rfile);
258
}
259
260
/* delete given midi synth port */
261
static void snd_seq_midisynth_delete(struct seq_midisynth *msynth)
262
{
263
if (msynth == NULL)
264
return;
265
266
if (msynth->seq_client > 0) {
267
/* delete port */
268
snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port);
269
}
270
271
if (msynth->parser)
272
snd_midi_event_free(msynth->parser);
273
}
274
275
/* register new midi synth port */
276
static int
277
snd_seq_midisynth_register_port(struct snd_seq_device *dev)
278
{
279
struct seq_midisynth_client *client;
280
struct seq_midisynth *msynth, *ms;
281
struct snd_seq_port_info *port;
282
struct snd_rawmidi_info *info;
283
struct snd_rawmidi *rmidi = dev->private_data;
284
int newclient = 0;
285
unsigned int p, ports;
286
struct snd_seq_port_callback pcallbacks;
287
struct snd_card *card = dev->card;
288
int device = dev->device;
289
unsigned int input_count = 0, output_count = 0;
290
291
if (snd_BUG_ON(!card || device < 0 || device >= SNDRV_RAWMIDI_DEVICES))
292
return -EINVAL;
293
info = kmalloc(sizeof(*info), GFP_KERNEL);
294
if (! info)
295
return -ENOMEM;
296
info->device = device;
297
info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
298
info->subdevice = 0;
299
if (snd_rawmidi_info_select(card, info) >= 0)
300
output_count = info->subdevices_count;
301
info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
302
if (snd_rawmidi_info_select(card, info) >= 0) {
303
input_count = info->subdevices_count;
304
}
305
ports = output_count;
306
if (ports < input_count)
307
ports = input_count;
308
if (ports == 0) {
309
kfree(info);
310
return -ENODEV;
311
}
312
if (ports > (256 / SNDRV_RAWMIDI_DEVICES))
313
ports = 256 / SNDRV_RAWMIDI_DEVICES;
314
315
mutex_lock(&register_mutex);
316
client = synths[card->number];
317
if (client == NULL) {
318
newclient = 1;
319
client = kzalloc(sizeof(*client), GFP_KERNEL);
320
if (client == NULL) {
321
mutex_unlock(&register_mutex);
322
kfree(info);
323
return -ENOMEM;
324
}
325
client->seq_client =
326
snd_seq_create_kernel_client(
327
card, 0, "%s", card->shortname[0] ?
328
(const char *)card->shortname : "External MIDI");
329
if (client->seq_client < 0) {
330
kfree(client);
331
mutex_unlock(&register_mutex);
332
kfree(info);
333
return -ENOMEM;
334
}
335
}
336
337
msynth = kcalloc(ports, sizeof(struct seq_midisynth), GFP_KERNEL);
338
port = kmalloc(sizeof(*port), GFP_KERNEL);
339
if (msynth == NULL || port == NULL)
340
goto __nomem;
341
342
for (p = 0; p < ports; p++) {
343
ms = &msynth[p];
344
345
if (snd_seq_midisynth_new(ms, card, device, p) < 0)
346
goto __nomem;
347
348
/* declare port */
349
memset(port, 0, sizeof(*port));
350
port->addr.client = client->seq_client;
351
port->addr.port = device * (256 / SNDRV_RAWMIDI_DEVICES) + p;
352
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
353
memset(info, 0, sizeof(*info));
354
info->device = device;
355
if (p < output_count)
356
info->stream = SNDRV_RAWMIDI_STREAM_OUTPUT;
357
else
358
info->stream = SNDRV_RAWMIDI_STREAM_INPUT;
359
info->subdevice = p;
360
if (snd_rawmidi_info_select(card, info) >= 0)
361
strcpy(port->name, info->subname);
362
if (! port->name[0]) {
363
if (info->name[0]) {
364
if (ports > 1)
365
snprintf(port->name, sizeof(port->name), "%s-%d", info->name, p);
366
else
367
snprintf(port->name, sizeof(port->name), "%s", info->name);
368
} else {
369
/* last resort */
370
if (ports > 1)
371
sprintf(port->name, "MIDI %d-%d-%d", card->number, device, p);
372
else
373
sprintf(port->name, "MIDI %d-%d", card->number, device);
374
}
375
}
376
if ((info->flags & SNDRV_RAWMIDI_INFO_OUTPUT) && p < output_count)
377
port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
378
if ((info->flags & SNDRV_RAWMIDI_INFO_INPUT) && p < input_count)
379
port->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
380
if ((port->capability & (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ)) == (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_READ) &&
381
info->flags & SNDRV_RAWMIDI_INFO_DUPLEX)
382
port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
383
port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
384
| SNDRV_SEQ_PORT_TYPE_HARDWARE
385
| SNDRV_SEQ_PORT_TYPE_PORT;
386
port->midi_channels = 16;
387
memset(&pcallbacks, 0, sizeof(pcallbacks));
388
pcallbacks.owner = THIS_MODULE;
389
pcallbacks.private_data = ms;
390
pcallbacks.subscribe = midisynth_subscribe;
391
pcallbacks.unsubscribe = midisynth_unsubscribe;
392
pcallbacks.use = midisynth_use;
393
pcallbacks.unuse = midisynth_unuse;
394
pcallbacks.event_input = event_process_midi;
395
port->kernel = &pcallbacks;
396
if (rmidi->ops && rmidi->ops->get_port_info)
397
rmidi->ops->get_port_info(rmidi, p, port);
398
if (snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_CREATE_PORT, port)<0)
399
goto __nomem;
400
ms->seq_client = client->seq_client;
401
ms->seq_port = port->addr.port;
402
}
403
client->ports_per_device[device] = ports;
404
client->ports[device] = msynth;
405
client->num_ports++;
406
if (newclient)
407
synths[card->number] = client;
408
mutex_unlock(&register_mutex);
409
kfree(info);
410
kfree(port);
411
return 0; /* success */
412
413
__nomem:
414
if (msynth != NULL) {
415
for (p = 0; p < ports; p++)
416
snd_seq_midisynth_delete(&msynth[p]);
417
kfree(msynth);
418
}
419
if (newclient) {
420
snd_seq_delete_kernel_client(client->seq_client);
421
kfree(client);
422
}
423
kfree(info);
424
kfree(port);
425
mutex_unlock(&register_mutex);
426
return -ENOMEM;
427
}
428
429
/* release midi synth port */
430
static int
431
snd_seq_midisynth_unregister_port(struct snd_seq_device *dev)
432
{
433
struct seq_midisynth_client *client;
434
struct seq_midisynth *msynth;
435
struct snd_card *card = dev->card;
436
int device = dev->device, p, ports;
437
438
mutex_lock(&register_mutex);
439
client = synths[card->number];
440
if (client == NULL || client->ports[device] == NULL) {
441
mutex_unlock(&register_mutex);
442
return -ENODEV;
443
}
444
ports = client->ports_per_device[device];
445
client->ports_per_device[device] = 0;
446
msynth = client->ports[device];
447
client->ports[device] = NULL;
448
for (p = 0; p < ports; p++)
449
snd_seq_midisynth_delete(&msynth[p]);
450
kfree(msynth);
451
client->num_ports--;
452
if (client->num_ports <= 0) {
453
snd_seq_delete_kernel_client(client->seq_client);
454
synths[card->number] = NULL;
455
kfree(client);
456
}
457
mutex_unlock(&register_mutex);
458
return 0;
459
}
460
461
462
static int __init alsa_seq_midi_init(void)
463
{
464
static struct snd_seq_dev_ops ops = {
465
snd_seq_midisynth_register_port,
466
snd_seq_midisynth_unregister_port,
467
};
468
memset(&synths, 0, sizeof(synths));
469
snd_seq_autoload_lock();
470
snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH, &ops, 0);
471
snd_seq_autoload_unlock();
472
return 0;
473
}
474
475
static void __exit alsa_seq_midi_exit(void)
476
{
477
snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_MIDISYNTH);
478
}
479
480
module_init(alsa_seq_midi_init)
481
module_exit(alsa_seq_midi_exit)
482
483