Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/core/seq/seq_virmidi.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Virtual Raw MIDI client on Sequencer
4
*
5
* Copyright (c) 2000 by Takashi Iwai <[email protected]>,
6
* Jaroslav Kysela <[email protected]>
7
*/
8
9
/*
10
* Virtual Raw MIDI client
11
*
12
* The virtual rawmidi client is a sequencer client which associate
13
* a rawmidi device file. The created rawmidi device file can be
14
* accessed as a normal raw midi, but its MIDI source and destination
15
* are arbitrary. For example, a user-client software synth connected
16
* to this port can be used as a normal midi device as well.
17
*
18
* The virtual rawmidi device accepts also multiple opens. Each file
19
* has its own input buffer, so that no conflict would occur. The drain
20
* of input/output buffer acts only to the local buffer.
21
*
22
*/
23
24
#include <linux/init.h>
25
#include <linux/wait.h>
26
#include <linux/module.h>
27
#include <linux/slab.h>
28
#include <sound/core.h>
29
#include <sound/rawmidi.h>
30
#include <sound/info.h>
31
#include <sound/control.h>
32
#include <sound/minors.h>
33
#include <sound/seq_kernel.h>
34
#include <sound/seq_midi_event.h>
35
#include <sound/seq_virmidi.h>
36
37
MODULE_AUTHOR("Takashi Iwai <[email protected]>");
38
MODULE_DESCRIPTION("Virtual Raw MIDI client on Sequencer");
39
MODULE_LICENSE("GPL");
40
41
/*
42
* initialize an event record
43
*/
44
static void snd_virmidi_init_event(struct snd_virmidi *vmidi,
45
struct snd_seq_event *ev)
46
{
47
memset(ev, 0, sizeof(*ev));
48
ev->source.port = vmidi->port;
49
switch (vmidi->seq_mode) {
50
case SNDRV_VIRMIDI_SEQ_DISPATCH:
51
ev->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
52
break;
53
case SNDRV_VIRMIDI_SEQ_ATTACH:
54
/* FIXME: source and destination are same - not good.. */
55
ev->dest.client = vmidi->client;
56
ev->dest.port = vmidi->port;
57
break;
58
}
59
ev->type = SNDRV_SEQ_EVENT_NONE;
60
}
61
62
/*
63
* decode input event and put to read buffer of each opened file
64
*/
65
66
/* callback for snd_seq_dump_var_event(), bridging to snd_rawmidi_receive() */
67
static int dump_to_rawmidi(void *ptr, void *buf, int count)
68
{
69
return snd_rawmidi_receive(ptr, buf, count);
70
}
71
72
static int snd_virmidi_dev_receive_event(struct snd_virmidi_dev *rdev,
73
struct snd_seq_event *ev,
74
bool atomic)
75
{
76
struct snd_virmidi *vmidi;
77
unsigned char msg[4];
78
int len;
79
80
if (atomic)
81
read_lock(&rdev->filelist_lock);
82
else
83
down_read(&rdev->filelist_sem);
84
list_for_each_entry(vmidi, &rdev->filelist, list) {
85
if (!READ_ONCE(vmidi->trigger))
86
continue;
87
if (ev->type == SNDRV_SEQ_EVENT_SYSEX) {
88
if ((ev->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) != SNDRV_SEQ_EVENT_LENGTH_VARIABLE)
89
continue;
90
snd_seq_dump_var_event(ev, dump_to_rawmidi, vmidi->substream);
91
snd_midi_event_reset_decode(vmidi->parser);
92
} else {
93
len = snd_midi_event_decode(vmidi->parser, msg, sizeof(msg), ev);
94
if (len > 0)
95
snd_rawmidi_receive(vmidi->substream, msg, len);
96
}
97
}
98
if (atomic)
99
read_unlock(&rdev->filelist_lock);
100
else
101
up_read(&rdev->filelist_sem);
102
103
return 0;
104
}
105
106
/*
107
* event handler of virmidi port
108
*/
109
static int snd_virmidi_event_input(struct snd_seq_event *ev, int direct,
110
void *private_data, int atomic, int hop)
111
{
112
struct snd_virmidi_dev *rdev;
113
114
rdev = private_data;
115
if (!(rdev->flags & SNDRV_VIRMIDI_USE))
116
return 0; /* ignored */
117
return snd_virmidi_dev_receive_event(rdev, ev, atomic);
118
}
119
120
/*
121
* trigger rawmidi stream for input
122
*/
123
static void snd_virmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
124
{
125
struct snd_virmidi *vmidi = substream->runtime->private_data;
126
127
WRITE_ONCE(vmidi->trigger, !!up);
128
}
129
130
/* process rawmidi bytes and send events;
131
* we need no lock here for vmidi->event since it's handled only in this work
132
*/
133
static void snd_vmidi_output_work(struct work_struct *work)
134
{
135
struct snd_virmidi *vmidi;
136
struct snd_rawmidi_substream *substream;
137
unsigned char input;
138
int ret;
139
140
vmidi = container_of(work, struct snd_virmidi, output_work);
141
substream = vmidi->substream;
142
143
/* discard the outputs in dispatch mode unless subscribed */
144
if (vmidi->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH &&
145
!(vmidi->rdev->flags & SNDRV_VIRMIDI_SUBSCRIBE)) {
146
snd_rawmidi_proceed(substream);
147
return;
148
}
149
150
while (READ_ONCE(vmidi->trigger)) {
151
if (snd_rawmidi_transmit(substream, &input, 1) != 1)
152
break;
153
if (!snd_midi_event_encode_byte(vmidi->parser, input,
154
&vmidi->event))
155
continue;
156
if (vmidi->event.type != SNDRV_SEQ_EVENT_NONE) {
157
ret = snd_seq_kernel_client_dispatch(vmidi->client,
158
&vmidi->event,
159
false, 0);
160
vmidi->event.type = SNDRV_SEQ_EVENT_NONE;
161
if (ret < 0)
162
break;
163
}
164
/* rawmidi input might be huge, allow to have a break */
165
cond_resched();
166
}
167
}
168
169
/*
170
* trigger rawmidi stream for output
171
*/
172
static void snd_virmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
173
{
174
struct snd_virmidi *vmidi = substream->runtime->private_data;
175
176
WRITE_ONCE(vmidi->trigger, !!up);
177
if (up)
178
queue_work(system_highpri_wq, &vmidi->output_work);
179
}
180
181
/*
182
* open rawmidi handle for input
183
*/
184
static int snd_virmidi_input_open(struct snd_rawmidi_substream *substream)
185
{
186
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
187
struct snd_rawmidi_runtime *runtime = substream->runtime;
188
struct snd_virmidi *vmidi;
189
190
vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
191
if (vmidi == NULL)
192
return -ENOMEM;
193
vmidi->substream = substream;
194
if (snd_midi_event_new(0, &vmidi->parser) < 0) {
195
kfree(vmidi);
196
return -ENOMEM;
197
}
198
vmidi->seq_mode = rdev->seq_mode;
199
vmidi->client = rdev->client;
200
vmidi->port = rdev->port;
201
runtime->private_data = vmidi;
202
scoped_guard(rwsem_write, &rdev->filelist_sem) {
203
guard(write_lock_irq)(&rdev->filelist_lock);
204
list_add_tail(&vmidi->list, &rdev->filelist);
205
}
206
vmidi->rdev = rdev;
207
return 0;
208
}
209
210
/*
211
* open rawmidi handle for output
212
*/
213
static int snd_virmidi_output_open(struct snd_rawmidi_substream *substream)
214
{
215
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
216
struct snd_rawmidi_runtime *runtime = substream->runtime;
217
struct snd_virmidi *vmidi;
218
219
vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL);
220
if (vmidi == NULL)
221
return -ENOMEM;
222
vmidi->substream = substream;
223
if (snd_midi_event_new(MAX_MIDI_EVENT_BUF, &vmidi->parser) < 0) {
224
kfree(vmidi);
225
return -ENOMEM;
226
}
227
vmidi->seq_mode = rdev->seq_mode;
228
vmidi->client = rdev->client;
229
vmidi->port = rdev->port;
230
snd_virmidi_init_event(vmidi, &vmidi->event);
231
vmidi->rdev = rdev;
232
INIT_WORK(&vmidi->output_work, snd_vmidi_output_work);
233
runtime->private_data = vmidi;
234
return 0;
235
}
236
237
/*
238
* close rawmidi handle for input
239
*/
240
static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
241
{
242
struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
243
struct snd_virmidi *vmidi = substream->runtime->private_data;
244
245
scoped_guard(rwsem_write, &rdev->filelist_sem) {
246
guard(write_lock_irq)(&rdev->filelist_lock);
247
list_del(&vmidi->list);
248
}
249
snd_midi_event_free(vmidi->parser);
250
substream->runtime->private_data = NULL;
251
kfree(vmidi);
252
return 0;
253
}
254
255
/*
256
* close rawmidi handle for output
257
*/
258
static int snd_virmidi_output_close(struct snd_rawmidi_substream *substream)
259
{
260
struct snd_virmidi *vmidi = substream->runtime->private_data;
261
262
WRITE_ONCE(vmidi->trigger, false); /* to be sure */
263
cancel_work_sync(&vmidi->output_work);
264
snd_midi_event_free(vmidi->parser);
265
substream->runtime->private_data = NULL;
266
kfree(vmidi);
267
return 0;
268
}
269
270
/*
271
* drain output work queue
272
*/
273
static void snd_virmidi_output_drain(struct snd_rawmidi_substream *substream)
274
{
275
struct snd_virmidi *vmidi = substream->runtime->private_data;
276
277
flush_work(&vmidi->output_work);
278
}
279
280
/*
281
* subscribe callback - allow output to rawmidi device
282
*/
283
static int snd_virmidi_subscribe(void *private_data,
284
struct snd_seq_port_subscribe *info)
285
{
286
struct snd_virmidi_dev *rdev;
287
288
rdev = private_data;
289
if (!try_module_get(rdev->card->module))
290
return -EFAULT;
291
rdev->flags |= SNDRV_VIRMIDI_SUBSCRIBE;
292
return 0;
293
}
294
295
/*
296
* unsubscribe callback - disallow output to rawmidi device
297
*/
298
static int snd_virmidi_unsubscribe(void *private_data,
299
struct snd_seq_port_subscribe *info)
300
{
301
struct snd_virmidi_dev *rdev;
302
303
rdev = private_data;
304
rdev->flags &= ~SNDRV_VIRMIDI_SUBSCRIBE;
305
module_put(rdev->card->module);
306
return 0;
307
}
308
309
310
/*
311
* use callback - allow input to rawmidi device
312
*/
313
static int snd_virmidi_use(void *private_data,
314
struct snd_seq_port_subscribe *info)
315
{
316
struct snd_virmidi_dev *rdev;
317
318
rdev = private_data;
319
if (!try_module_get(rdev->card->module))
320
return -EFAULT;
321
rdev->flags |= SNDRV_VIRMIDI_USE;
322
return 0;
323
}
324
325
/*
326
* unuse callback - disallow input to rawmidi device
327
*/
328
static int snd_virmidi_unuse(void *private_data,
329
struct snd_seq_port_subscribe *info)
330
{
331
struct snd_virmidi_dev *rdev;
332
333
rdev = private_data;
334
rdev->flags &= ~SNDRV_VIRMIDI_USE;
335
module_put(rdev->card->module);
336
return 0;
337
}
338
339
340
/*
341
* Register functions
342
*/
343
344
static const struct snd_rawmidi_ops snd_virmidi_input_ops = {
345
.open = snd_virmidi_input_open,
346
.close = snd_virmidi_input_close,
347
.trigger = snd_virmidi_input_trigger,
348
};
349
350
static const struct snd_rawmidi_ops snd_virmidi_output_ops = {
351
.open = snd_virmidi_output_open,
352
.close = snd_virmidi_output_close,
353
.trigger = snd_virmidi_output_trigger,
354
.drain = snd_virmidi_output_drain,
355
};
356
357
/*
358
* create a sequencer client and a port
359
*/
360
static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
361
{
362
int client;
363
struct snd_seq_port_callback pcallbacks;
364
struct snd_seq_port_info *pinfo __free(kfree) = NULL;
365
int err;
366
367
if (rdev->client >= 0)
368
return 0;
369
370
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
371
if (!pinfo)
372
return -ENOMEM;
373
374
client = snd_seq_create_kernel_client(rdev->card, rdev->device,
375
"%s %d-%d", rdev->rmidi->name,
376
rdev->card->number,
377
rdev->device);
378
if (client < 0)
379
return client;
380
rdev->client = client;
381
382
/* create a port */
383
pinfo->addr.client = client;
384
sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
385
/* set all capabilities */
386
pinfo->capability |= SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SYNC_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE;
387
pinfo->capability |= SNDRV_SEQ_PORT_CAP_READ | SNDRV_SEQ_PORT_CAP_SYNC_READ | SNDRV_SEQ_PORT_CAP_SUBS_READ;
388
pinfo->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX;
389
pinfo->direction = SNDRV_SEQ_PORT_DIR_BIDIRECTION;
390
pinfo->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC
391
| SNDRV_SEQ_PORT_TYPE_SOFTWARE
392
| SNDRV_SEQ_PORT_TYPE_PORT;
393
pinfo->midi_channels = 16;
394
memset(&pcallbacks, 0, sizeof(pcallbacks));
395
pcallbacks.owner = THIS_MODULE;
396
pcallbacks.private_data = rdev;
397
pcallbacks.subscribe = snd_virmidi_subscribe;
398
pcallbacks.unsubscribe = snd_virmidi_unsubscribe;
399
pcallbacks.use = snd_virmidi_use;
400
pcallbacks.unuse = snd_virmidi_unuse;
401
pcallbacks.event_input = snd_virmidi_event_input;
402
pinfo->kernel = &pcallbacks;
403
err = snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_CREATE_PORT, pinfo);
404
if (err < 0) {
405
snd_seq_delete_kernel_client(client);
406
rdev->client = -1;
407
return err;
408
}
409
410
rdev->port = pinfo->addr.port;
411
return 0; /* success */
412
}
413
414
415
/*
416
* release the sequencer client
417
*/
418
static void snd_virmidi_dev_detach_seq(struct snd_virmidi_dev *rdev)
419
{
420
if (rdev->client >= 0) {
421
snd_seq_delete_kernel_client(rdev->client);
422
rdev->client = -1;
423
}
424
}
425
426
/*
427
* register the device
428
*/
429
static int snd_virmidi_dev_register(struct snd_rawmidi *rmidi)
430
{
431
struct snd_virmidi_dev *rdev = rmidi->private_data;
432
int err;
433
434
switch (rdev->seq_mode) {
435
case SNDRV_VIRMIDI_SEQ_DISPATCH:
436
err = snd_virmidi_dev_attach_seq(rdev);
437
if (err < 0)
438
return err;
439
break;
440
case SNDRV_VIRMIDI_SEQ_ATTACH:
441
if (rdev->client == 0)
442
return -EINVAL;
443
/* should check presence of port more strictly.. */
444
break;
445
default:
446
pr_err("ALSA: seq_virmidi: seq_mode is not set: %d\n", rdev->seq_mode);
447
return -EINVAL;
448
}
449
return 0;
450
}
451
452
453
/*
454
* unregister the device
455
*/
456
static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi)
457
{
458
struct snd_virmidi_dev *rdev = rmidi->private_data;
459
460
if (rdev->seq_mode == SNDRV_VIRMIDI_SEQ_DISPATCH)
461
snd_virmidi_dev_detach_seq(rdev);
462
return 0;
463
}
464
465
/*
466
*
467
*/
468
static const struct snd_rawmidi_global_ops snd_virmidi_global_ops = {
469
.dev_register = snd_virmidi_dev_register,
470
.dev_unregister = snd_virmidi_dev_unregister,
471
};
472
473
/*
474
* free device
475
*/
476
static void snd_virmidi_free(struct snd_rawmidi *rmidi)
477
{
478
struct snd_virmidi_dev *rdev = rmidi->private_data;
479
kfree(rdev);
480
}
481
482
/*
483
* create a new device
484
*
485
*/
486
/* exported */
487
int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmidi)
488
{
489
struct snd_rawmidi *rmidi;
490
struct snd_virmidi_dev *rdev;
491
int err;
492
493
*rrmidi = NULL;
494
err = snd_rawmidi_new(card, "VirMidi", device,
495
16, /* may be configurable */
496
16, /* may be configurable */
497
&rmidi);
498
if (err < 0)
499
return err;
500
strscpy(rmidi->name, rmidi->id);
501
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
502
if (rdev == NULL) {
503
snd_device_free(card, rmidi);
504
return -ENOMEM;
505
}
506
rdev->card = card;
507
rdev->rmidi = rmidi;
508
rdev->device = device;
509
rdev->client = -1;
510
init_rwsem(&rdev->filelist_sem);
511
rwlock_init(&rdev->filelist_lock);
512
INIT_LIST_HEAD(&rdev->filelist);
513
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
514
rmidi->private_data = rdev;
515
rmidi->private_free = snd_virmidi_free;
516
rmidi->ops = &snd_virmidi_global_ops;
517
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_virmidi_input_ops);
518
snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_virmidi_output_ops);
519
rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT |
520
SNDRV_RAWMIDI_INFO_OUTPUT |
521
SNDRV_RAWMIDI_INFO_DUPLEX;
522
*rrmidi = rmidi;
523
return 0;
524
}
525
EXPORT_SYMBOL(snd_virmidi_new);
526
527