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