Deleted Added
sdiff udiff text old ( 166280 ) new ( 166322 )
full compact
1/*-
2 * (c) 2003 Mathew Kanner
3 *
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (augustss@netbsd.org).
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Parts of this file started out as NetBSD: midi.c 1.31
41 * They are mostly gone. Still the most obvious will be the state
42 * machine midi_in
43 */
44
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: head/sys/dev/sound/midi/midi.c 166280 2007-01-27 15:55:59Z ariff $");
47
48#include <sys/param.h>
49#include <sys/queue.h>
50#include <sys/kernel.h>
51#include <sys/lock.h>
52#include <sys/mutex.h>
53#include <sys/proc.h>
54#include <sys/signalvar.h>
55#include <sys/conf.h>
56#include <sys/selinfo.h>
57#include <sys/sysctl.h>
58#include <sys/types.h>
59#include <sys/malloc.h>
60#include <sys/param.h>
61#include <sys/systm.h>
62#include <sys/proc.h>
63#include <sys/fcntl.h>
64#include <sys/types.h>
65#include <sys/uio.h>
66#include <sys/poll.h>
67#include <sys/sbuf.h>
68#include <sys/kobj.h>
69#include <sys/module.h>
70
71#include <dev/sound/midi/midi.h>
72#include "mpu_if.h"
73
74#include <dev/sound/midi/midiq.h>
75#include "synth_if.h"
76MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
77
78
79#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
80#define MIDIMKMINOR(u, d, c) PCMMKMINOR(u, d, c)
81
82#define MIDI_DEV_RAW 2
83#define MIDI_DEV_MIDICTL 12
84
85enum midi_states {
86 MIDI_IN_START, MIDI_IN_SYSEX, MIDI_IN_DATA
87};
88
89/*
90 * The MPU interface current has init() uninit() inqsize(( outqsize()
91 * callback() : fiddle with the tx|rx status.
92 */
93
94#include "mpu_if.h"
95
96/*
97 * /dev/rmidi Structure definitions
98 */
99
100#define MIDI_NAMELEN 16
101struct snd_midi {
102 KOBJ_FIELDS;
103 struct mtx lock; /* Protects all but queues */
104 void *cookie;
105
106 int unit; /* Should only be used in midistat */
107 int channel;/* Should only be used in midistat */
108
109 int busy;
110 int flags; /* File flags */
111 char name[MIDI_NAMELEN];
112 struct mtx qlock; /* Protects inq, outq and flags */
113 MIDIQ_HEAD(, char)inq, outq;
114 int rchan, wchan;
115 struct selinfo rsel, wsel;
116 int hiwat; /* QLEN(outq)>High-water -> disable writes
117 * from userland */
118 enum midi_states inq_state;
119 int inq_status, inq_left; /* Variables for the state
120 * machine in Midi_in, this
121 * is to provide that signals
122 * only get issued only
123 * complete command packets. */
124 struct proc *async;
125 struct cdev *dev;
126 struct synth_midi *synth;
127 int synth_flags;
128 TAILQ_ENTRY(snd_midi) link;
129};
130
131struct synth_midi {
132 KOBJ_FIELDS;
133 struct snd_midi *m;
134};
135
136static synth_open_t midisynth_open;
137static synth_close_t midisynth_close;
138static synth_writeraw_t midisynth_writeraw;
139static synth_killnote_t midisynth_killnote;
140static synth_startnote_t midisynth_startnote;
141static synth_setinstr_t midisynth_setinstr;
142static synth_alloc_t midisynth_alloc;
143static synth_controller_t midisynth_controller;
144static synth_bender_t midisynth_bender;
145
146
147static kobj_method_t midisynth_methods[] = {
148 KOBJMETHOD(synth_open,midisynth_open),
149 KOBJMETHOD(synth_close,midisynth_close),
150 KOBJMETHOD(synth_writeraw,midisynth_writeraw),
151 KOBJMETHOD(synth_setinstr,midisynth_setinstr),
152 KOBJMETHOD(synth_startnote,midisynth_startnote),
153 KOBJMETHOD(synth_killnote,midisynth_killnote),
154 KOBJMETHOD(synth_alloc, midisynth_alloc),
155 KOBJMETHOD(synth_controller, midisynth_controller),
156 KOBJMETHOD(synth_bender, midisynth_bender),
157 { 0, 0 }
158};
159
160DEFINE_CLASS(midisynth, midisynth_methods, 0);
161
162/*
163 * Module Exports & Interface
164 *
165 * struct midi_chan *midi_init(MPU_CLASS cls, int unit, int chan) int
166 * midi_uninit(struct snd_midi *) 0 == no error EBUSY or other error int
167 * Midi_in(struct midi_chan *, char *buf, int count) int Midi_out(struct
168 * midi_chan *, char *buf, int count)
169 *
170 * midi_{in,out} return actual size transfered
171 *
172 */
173
174
175/*
176 * midi_devs tailq, holder of all rmidi instances protected by midistat_lock
177 */
178
179TAILQ_HEAD(, snd_midi) midi_devs;
180
181/*
182 * /dev/midistat variables and declarations, protected by midistat_lock
183 */
184
185static struct mtx midistat_lock;
186static int midistat_isopen = 0;
187static struct sbuf midistat_sbuf;
188static int midistat_bufptr;
189static struct cdev *midistat_dev;
190
191/*
192 * /dev/midistat dev_t declarations
193 */
194
195static d_open_t midistat_open;
196static d_close_t midistat_close;
197static d_read_t midistat_read;
198
199static struct cdevsw midistat_cdevsw = {
200 .d_version = D_VERSION,
201 .d_open = midistat_open,
202 .d_close = midistat_close,
203 .d_read = midistat_read,
204 .d_name = "midistat",
205};
206
207
208/*
209 * /dev/rmidi dev_t declarations, struct variable access is protected by
210 * locks contained within the structure.
211 */
212
213static d_open_t midi_open;
214static d_close_t midi_close;
215static d_ioctl_t midi_ioctl;
216static d_read_t midi_read;
217static d_write_t midi_write;
218static d_poll_t midi_poll;
219
220static struct cdevsw midi_cdevsw = {
221 .d_version = D_VERSION,
222 .d_open = midi_open,
223 .d_close = midi_close,
224 .d_read = midi_read,
225 .d_write = midi_write,
226 .d_ioctl = midi_ioctl,
227 .d_poll = midi_poll,
228 .d_name = "rmidi",
229};
230
231/*
232 * Prototypes of library functions
233 */
234
235static int midi_destroy(struct snd_midi *, int);
236static int midistat_prepare(struct sbuf * s);
237static int midi_load(void);
238static int midi_unload(void);
239
240/*
241 * Misc declr.
242 */
243SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
244SYSCTL_NODE(_hw_midi, OID_AUTO, stat, CTLFLAG_RD, 0, "Status device");
245
246int midi_debug;
247/* XXX: should this be moved into debug.midi? */
248SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
249
250int midi_dumpraw;
251SYSCTL_INT(_hw_midi, OID_AUTO, dumpraw, CTLFLAG_RW, &midi_dumpraw, 0, "");
252
253int midi_instroff;
254SYSCTL_INT(_hw_midi, OID_AUTO, instroff, CTLFLAG_RW, &midi_instroff, 0, "");
255
256int midistat_verbose;
257SYSCTL_INT(_hw_midi_stat, OID_AUTO, verbose, CTLFLAG_RW,
258 &midistat_verbose, 0, "");
259
260#define MIDI_DEBUG(l,a) if(midi_debug>=l) a
261/*
262 * CODE START
263 */
264
265/*
266 * Register a new rmidi device. cls midi_if interface unit == 0 means
267 * auto-assign new unit number unit != 0 already assigned a unit number, eg.
268 * not the first channel provided by this device. channel, sub-unit
269 * cookie is passed back on MPU calls Typical device drivers will call with
270 * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
271 * what unit number is used.
272 *
273 * It is an error to call midi_init with an already used unit/channel combo.
274 *
275 * Returns NULL on error
276 *
277 */
278struct snd_midi *
279midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
280{
281 struct snd_midi *m;
282 int i;
283 int inqsize, outqsize;
284 MIDI_TYPE *buf;
285
286 MIDI_DEBUG(1,printf("midiinit: unit %d/%d.\n", unit, channel));
287 mtx_lock(&midistat_lock);
288 /*
289 * Protect against call with existing unit/channel or auto-allocate a
290 * new unit number.
291 */
292 i = -1;
293 TAILQ_FOREACH(m, &midi_devs, link) {
294 mtx_lock(&m->lock);
295 if (unit != 0) {
296 if (m->unit == unit && m->channel == channel) {
297 mtx_unlock(&m->lock);
298 goto err0;
299 }
300 } else {
301 /*
302 * Find a better unit number
303 */
304 if (m->unit > i)
305 i = m->unit;
306 }
307 mtx_unlock(&m->lock);
308 }
309
310 if (unit == 0)
311 unit = i + 1;
312
313 MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
314 m = malloc(sizeof(*m), M_MIDI, M_NOWAIT | M_ZERO);
315 if (m == NULL)
316 goto err0;
317
318 m->synth = malloc(sizeof(*m->synth), M_MIDI, M_NOWAIT | M_ZERO);
319 kobj_init((kobj_t)m->synth, &midisynth_class);
320 m->synth->m = m;
321 kobj_init((kobj_t)m, cls);
322 inqsize = MPU_INQSIZE(m, cookie);
323 outqsize = MPU_OUTQSIZE(m, cookie);
324
325 MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
326 if (!inqsize && !outqsize)
327 goto err1;
328
329 mtx_init(&m->lock, "raw midi", 0, 0);
330 mtx_init(&m->qlock, "q raw midi", 0, 0);
331
332 mtx_lock(&m->lock);
333 mtx_lock(&m->qlock);
334
335 if (inqsize)
336 buf = malloc(sizeof(MIDI_TYPE) * inqsize, M_MIDI, M_NOWAIT);
337 else
338 buf = NULL;
339
340 MIDIQ_INIT(m->inq, buf, inqsize);
341
342 if (outqsize)
343 buf = malloc(sizeof(MIDI_TYPE) * outqsize, M_MIDI, M_NOWAIT);
344 else
345 buf = NULL;
346 m->hiwat = outqsize / 2;
347
348 MIDIQ_INIT(m->outq, buf, outqsize);
349
350 if ((inqsize && !MIDIQ_BUF(m->inq)) ||
351 (outqsize && !MIDIQ_BUF(m->outq)))
352 goto err2;
353
354
355 m->busy = 0;
356 m->flags = 0;
357 m->unit = unit;
358 m->channel = channel;
359 m->cookie = cookie;
360
361 if (MPU_INIT(m, cookie))
362 goto err2;
363
364 mtx_unlock(&m->lock);
365 mtx_unlock(&m->qlock);
366
367 TAILQ_INSERT_TAIL(&midi_devs, m, link);
368
369 mtx_unlock(&midistat_lock);
370
371 m->dev = make_dev(&midi_cdevsw,
372 MIDIMKMINOR(unit, MIDI_DEV_RAW, channel),
373 UID_ROOT, GID_WHEEL, 0666, "midi%d.%d", unit, channel);
374 m->dev->si_drv1 = m;
375
376 return m;
377
378err2: mtx_destroy(&m->qlock);
379 mtx_destroy(&m->lock);
380
381 if (MIDIQ_BUF(m->inq))
382 free(MIDIQ_BUF(m->inq), M_MIDI);
383 if (MIDIQ_BUF(m->outq))
384 free(MIDIQ_BUF(m->outq), M_MIDI);
385err1: free(m, M_MIDI);
386err0: mtx_unlock(&midistat_lock);
387 MIDI_DEBUG(1, printf("midi_init ended in error\n"));
388 return NULL;
389}
390
391/*
392 * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
393 * entry point. midi_unint if fact, does not send any methods. A call to
394 * midi_uninit is a defacto promise that you won't manipulate ch anymore
395 *
396 */
397
398int
399midi_uninit(struct snd_midi * m)
400{
401 int err;
402
403 err = ENXIO;
404 mtx_lock(&midistat_lock);
405 mtx_lock(&m->lock);
406 if (m->busy) {
407 if (!(m->rchan || m->wchan))
408 goto err;
409
410 if (m->rchan) {
411 wakeup(&m->rchan);
412 m->rchan = 0;
413 }
414 if (m->wchan) {
415 wakeup(&m->wchan);
416 m->wchan = 0;
417 }
418 }
419 err = midi_destroy(m, 0);
420 if(!err)
421 goto exit;
422
423err: mtx_unlock(&m->lock);
424exit: mtx_unlock(&midistat_lock);
425 return err;
426}
427
428/*
429 * midi_in: process all data until the queue is full, then discards the rest.
430 * Since midi_in is a state machine, data discards can cause it to get out of
431 * whack. Process as much as possible. It calls, wakeup, selnotify and
432 * psignal at most once.
433 */
434
435#ifdef notdef
436static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
437#endif /* notdef */
438/* Number of bytes in a MIDI command */
439#define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
440#define MIDI_ACK 0xfe
441#define MIDI_IS_STATUS(d) ((d) >= 0x80)
442#define MIDI_IS_COMMON(d) ((d) >= 0xf0)
443
444#define MIDI_SYSEX_START 0xF0
445#define MIDI_SYSEX_END 0xF7
446
447
448int
449midi_in(struct snd_midi * m, MIDI_TYPE * buf, int size)
450{
451 /* int i, sig, enq; */
452 int used;
453 /* MIDI_TYPE data; */
454 MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
455
456/*
457 * XXX: locking flub
458 */
459 if (!(m->flags & M_RX))
460 return size;
461
462 used = 0;
463
464 mtx_lock(&m->qlock);
465#if 0
466 /*
467 * Don't bother queuing if not in read mode. Discard everything and
468 * return size so the caller doesn't freak out.
469 */
470
471 if (!(m->flags & M_RX))
472 return size;
473
474 for (i = sig = 0; i < size; i++) {
475
476 data = buf[i];
477 enq = 0;
478 if (data == MIDI_ACK)
479 continue;
480
481 switch (m->inq_state) {
482 case MIDI_IN_START:
483 if (MIDI_IS_STATUS(data)) {
484 switch (data) {
485 case 0xf0: /* Sysex */
486 m->inq_state = MIDI_IN_SYSEX;
487 break;
488 case 0xf1: /* MTC quarter frame */
489 case 0xf3: /* Song select */
490 m->inq_state = MIDI_IN_DATA;
491 enq = 1;
492 m->inq_left = 1;
493 break;
494 case 0xf2: /* Song position pointer */
495 m->inq_state = MIDI_IN_DATA;
496 enq = 1;
497 m->inq_left = 2;
498 break;
499 default:
500 if (MIDI_IS_COMMON(data)) {
501 enq = 1;
502 sig = 1;
503 } else {
504 m->inq_state = MIDI_IN_DATA;
505 enq = 1;
506 m->inq_status = data;
507 m->inq_left = MIDI_LENGTH(data);
508 }
509 break;
510 }
511 } else if (MIDI_IS_STATUS(m->inq_status)) {
512 m->inq_state = MIDI_IN_DATA;
513 if (!MIDIQ_FULL(m->inq)) {
514 used++;
515 MIDIQ_ENQ(m->inq, &m->inq_status, 1);
516 }
517 enq = 1;
518 m->inq_left = MIDI_LENGTH(m->inq_status) - 1;
519 }
520 break;
521 /*
522 * End of case MIDI_IN_START:
523 */
524
525 case MIDI_IN_DATA:
526 enq = 1;
527 if (--m->inq_left <= 0)
528 sig = 1; /* deliver data */
529 break;
530 case MIDI_IN_SYSEX:
531 if (data == MIDI_SYSEX_END)
532 m->inq_state = MIDI_IN_START;
533 break;
534 }
535
536 if (enq)
537 if (!MIDIQ_FULL(m->inq)) {
538 MIDIQ_ENQ(m->inq, &data, 1);
539 used++;
540 }
541 /*
542 * End of the state machines main "for loop"
543 */
544 }
545 if (sig) {
546#endif
547 MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n", (intmax_t)MIDIQ_LEN(m->inq), (intmax_t)MIDIQ_AVAIL(m->inq))) ;
548 if (MIDIQ_AVAIL(m->inq) > size) {
549 used=size;
550 MIDIQ_ENQ(m->inq, buf, size);
551 } else {
552 MIDI_DEBUG(4,printf("midi_in: Discarding data qu\n"));
553 mtx_unlock(&m->qlock);
554 return 0;
555 }
556 if (m->rchan) {
557 wakeup(&m->rchan);
558 m->rchan = 0;
559 }
560 selwakeup(&m->rsel);
561 if (m->async) {
562 PROC_LOCK(m->async);
563 psignal(m->async, SIGIO);
564 PROC_UNLOCK(m->async);
565 }
566#if 0
567 }
568#endif
569 mtx_unlock(&m->qlock);
570 return used;
571}
572
573/*
574 * midi_out: The only clearer of the M_TXEN flag.
575 */
576int
577midi_out(struct snd_midi * m, MIDI_TYPE * buf, int size)
578{
579 int used;
580
581/*
582 * XXX: locking flub
583 */
584 if (!(m->flags & M_TXEN))
585 return 0;
586
587 MIDI_DEBUG(2, printf("midi_out: %p\n", m));
588 mtx_lock(&m->qlock);
589 used = MIN(size, MIDIQ_LEN(m->outq));
590 MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
591 if (used)
592 MIDIQ_DEQ(m->outq, buf, used);
593 if (MIDIQ_EMPTY(m->outq)) {
594 m->flags &= ~M_TXEN;
595 MPU_CALLBACKP(m, m->cookie, m->flags);
596 }
597 if (used && MIDIQ_AVAIL(m->outq) > m->hiwat ) {
598 if (m->wchan) {
599 wakeup(&m->wchan);
600 m->wchan = 0;
601 }
602 selwakeup(&m->wsel);
603 if (m->async) {
604 PROC_LOCK(m->async);
605 psignal(m->async, SIGIO);
606 PROC_UNLOCK(m->async);
607 }
608 }
609 mtx_unlock(&m->qlock);
610 return used;
611}
612
613
614/*
615 * /dev/rmidi#.# device access functions
616 */
617int
618midi_open(struct cdev *i_dev, int flags, int mode, struct thread * td)
619{
620 struct snd_midi *m = i_dev->si_drv1;
621 int retval;
622
623 MIDI_DEBUG(1,printf("midiopen %p %s %s\n", td,
624 flags & FREAD?"M_RX":"", flags & FWRITE?"M_TX":""));
625 if (m == NULL)
626 return ENXIO;
627
628 mtx_lock(&m->lock);
629 mtx_lock(&m->qlock);
630
631 retval = 0;
632
633 if (flags & FREAD) {
634 if (MIDIQ_SIZE(m->inq) == 0)
635 retval = ENXIO;
636 else if (m->flags & M_RX)
637 retval = EBUSY;
638 if (retval)
639 goto err;
640 }
641 if (flags & FWRITE) {
642 if (MIDIQ_SIZE(m->outq) == 0)
643 retval = ENXIO;
644 else if (m->flags & M_TX)
645 retval = EBUSY;
646 if (retval)
647 goto err;
648 }
649 m->busy++;
650
651 m->rchan = 0;
652 m->wchan = 0;
653 m->async = 0;
654
655 if (flags & FREAD) {
656 m->flags |= M_RX | M_RXEN;
657 /*
658 * Only clear the inq, the outq might still have data to drain from
659 * a previous session
660 */
661 MIDIQ_CLEAR(m->inq);
662 };
663
664 if (flags & FWRITE)
665 m->flags |= M_TX;
666
667 MPU_CALLBACK(m, m->cookie, m->flags);
668
669 MIDI_DEBUG(2, printf("midi_open: opened.\n"));
670
671err: mtx_unlock(&m->qlock);
672 mtx_unlock(&m->lock);
673 return retval;
674}
675
676int
677midi_close(struct cdev *i_dev, int flags, int mode, struct thread * td)
678{
679 struct snd_midi *m = i_dev->si_drv1;
680 int retval;
681 int oldflags;
682
683 MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
684 flags & FREAD?"M_RX":"", flags & FWRITE?"M_TX":""));
685
686 if (m == NULL)
687 return ENXIO;
688
689 mtx_lock(&m->lock);
690 mtx_lock(&m->qlock);
691
692 if ( (flags & FREAD && !(m->flags & M_RX)) ||
693 (flags & FWRITE && !(m->flags & M_TX)) ) {
694 retval = ENXIO;
695 goto err;
696 }
697
698 m->busy--;
699
700 oldflags = m->flags;
701
702 if (flags & FREAD)
703 m->flags &= ~(M_RX | M_RXEN);
704 if (flags & FWRITE)
705 m->flags &= ~M_TX;
706
707 if( (m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)) )
708 MPU_CALLBACK(m, m->cookie, m->flags);
709
710 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
711
712 mtx_unlock(&m->qlock);
713 mtx_unlock(&m->lock);
714 retval = 0;
715err: return retval;
716}
717/*
718 * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon as data is available.
719 */
720int
721midi_read(struct cdev *i_dev, struct uio * uio, int ioflag)
722{
723#define MIDI_RSIZE 32
724 struct snd_midi *m = i_dev->si_drv1;
725 int retval;
726 int used;
727 char buf[MIDI_RSIZE];
728
729 MIDI_DEBUG(5, printf("midiread: count=%lu\n", (unsigned long)uio->uio_resid));
730
731 retval = EIO;
732
733 if (m == NULL)
734 goto err0;
735
736 mtx_lock(&m->lock);
737 mtx_lock(&m->qlock);
738
739 if (!(m->flags & M_RX))
740 goto err1;
741
742 while (uio->uio_resid > 0) {
743 while (MIDIQ_EMPTY(m->inq)) {
744 retval = EWOULDBLOCK;
745 if (ioflag & O_NONBLOCK)
746 goto err1;
747 mtx_unlock(&m->lock);
748 m->rchan = 1;
749 retval = msleep(&m->rchan, &m->qlock,
750 PCATCH | PDROP, "midi RX", 0);
751 /*
752 * We slept, maybe things have changed since last
753 * dying check
754 */
755 if (retval == EINTR)
756 goto err0;
757 if (m != i_dev->si_drv1)
758 retval = ENXIO;
759 /* if (retval && retval != ERESTART) */
760 if (retval)
761 goto err0;
762 mtx_lock(&m->lock);
763 mtx_lock(&m->qlock);
764 m->rchan = 0;
765 if (!m->busy)
766 goto err1;
767 }
768 MIDI_DEBUG(6, printf("midi_read start\n"));
769 /*
770 * At this point, it is certain that m->inq has data
771 */
772
773 used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
774 used = MIN(used, MIDI_RSIZE);
775
776 MIDI_DEBUG(6,printf("midiread: uiomove cc=%d\n", used));
777 MIDIQ_DEQ(m->inq, buf, used);
778 retval = uiomove(buf, used, uio);
779 if (retval)
780 goto err1;
781 }
782
783 /*
784 * If we Made it here then transfer is good
785 */
786 retval = 0;
787err1: mtx_unlock(&m->qlock);
788 mtx_unlock(&m->lock);
789err0: MIDI_DEBUG(4, printf("midi_read: ret %d\n",retval));
790 return retval;
791}
792
793/*
794 * midi_write: The only setter of M_TXEN
795 */
796
797int
798midi_write(struct cdev *i_dev, struct uio * uio, int ioflag)
799{
800#define MIDI_WSIZE 32
801 struct snd_midi *m = i_dev->si_drv1;
802 int retval;
803 int used;
804 char buf[MIDI_WSIZE];
805
806
807 MIDI_DEBUG(4, printf("midi_write\n"));
808 retval = 0;
809 if (m == NULL)
810 goto err0;
811
812 mtx_lock(&m->lock);
813 mtx_lock(&m->qlock);
814
815 if (!(m->flags & M_TX))
816 goto err1;
817
818 while (uio->uio_resid > 0) {
819 while (MIDIQ_AVAIL(m->outq) == 0) {
820 retval = EWOULDBLOCK;
821 if (ioflag & O_NONBLOCK)
822 goto err1;
823 mtx_unlock(&m->lock);
824 m->wchan = 1;
825 MIDI_DEBUG(3,printf("midi_write msleep\n"));
826 retval = msleep(&m->wchan, &m->qlock,
827 PCATCH | PDROP, "midi TX", 0);
828 /*
829 * We slept, maybe things have changed since last
830 * dying check
831 */
832 if (retval == EINTR)
833 goto err0;
834 if (m != i_dev->si_drv1)
835 retval = ENXIO;
836 if (retval)
837 goto err0;
838 mtx_lock(&m->lock);
839 mtx_lock(&m->qlock);
840 m->wchan = 0;
841 if (!m->busy)
842 goto err1;
843 }
844
845 /*
846 * We are certain than data can be placed on the queue
847 */
848
849 used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
850 used = MIN(used, MIDI_WSIZE);
851 MIDI_DEBUG(5,printf("midiout: resid %d len %jd avail %jd\n", uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq), (intmax_t)MIDIQ_AVAIL(m->outq)));
852
853
854 MIDI_DEBUG(5,printf("midi_write: uiomove cc=%d\n", used));
855 retval = uiomove(buf, used, uio);
856 if (retval)
857 goto err1;
858 MIDIQ_ENQ(m->outq, buf, used);
859 /*
860 * Inform the bottom half that data can be written
861 */
862 if (!(m->flags & M_TXEN)) {
863 m->flags |= M_TXEN;
864 MPU_CALLBACK(m, m->cookie, m->flags);
865 }
866 }
867 /*
868 * If we Made it here then transfer is good
869 */
870 retval = 0;
871err1: mtx_unlock(&m->qlock);
872 mtx_unlock(&m->lock);
873err0: return retval;
874}
875
876int
877midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread * td)
878{
879 return ENXIO;
880}
881
882int
883midi_poll(struct cdev *i_dev, int events, struct thread * td)
884{
885 struct snd_midi *m = i_dev->si_drv1;
886 int revents;
887
888 if (m == NULL)
889 return 0;
890
891 revents = 0;
892
893 mtx_lock(&m->lock);
894 mtx_lock(&m->qlock);
895
896 if (events & (POLLIN | POLLRDNORM))
897 if (!MIDIQ_EMPTY(m->inq))
898 events |= events & (POLLIN | POLLRDNORM);
899
900 if (events & (POLLOUT | POLLWRNORM))
901 if (MIDIQ_AVAIL(m->outq) < m->hiwat)
902 events |= events & (POLLOUT | POLLWRNORM);
903
904 if (revents == 0) {
905 if (events & (POLLIN | POLLRDNORM))
906 selrecord(td, &m->rsel);
907
908 if (events & (POLLOUT | POLLWRNORM))
909 selrecord(td, &m->wsel);
910 }
911 mtx_unlock(&m->lock);
912 mtx_unlock(&m->qlock);
913
914 return (revents);
915}
916
917/*
918 * /dev/midistat device functions
919 *
920 */
921static int
922midistat_open(struct cdev *i_dev, int flags, int mode, struct thread * td)
923{
924 int error;
925
926 MIDI_DEBUG(1,printf("midistat_open\n"));
927 mtx_lock(&midistat_lock);
928
929 if (midistat_isopen) {
930 mtx_unlock(&midistat_lock);
931 return EBUSY;
932 }
933 midistat_isopen = 1;
934 mtx_unlock(&midistat_lock);
935
936 if (sbuf_new(&midistat_sbuf, NULL, 4096, SBUF_AUTOEXTEND) == NULL) {
937 error = ENXIO;
938 mtx_lock(&midistat_lock);
939 goto out;
940 }
941
942 mtx_lock(&midistat_lock);
943 midistat_bufptr = 0;
944 error = (midistat_prepare(&midistat_sbuf) > 0) ? 0 : ENOMEM;
945
946out: if (error)
947 midistat_isopen = 0;
948 mtx_unlock(&midistat_lock);
949 return error;
950}
951
952static int
953midistat_close(struct cdev *i_dev, int flags, int mode, struct thread * td)
954{
955 MIDI_DEBUG(1,printf("midistat_close\n"));
956 mtx_lock(&midistat_lock);
957 if (!midistat_isopen) {
958 mtx_unlock(&midistat_lock);
959 return EBADF;
960 }
961 sbuf_delete(&midistat_sbuf);
962 midistat_isopen = 0;
963
964 mtx_unlock(&midistat_lock);
965 return 0;
966}
967
968static int
969midistat_read(struct cdev *i_dev, struct uio * buf, int flag)
970{
971 int l, err;
972
973 MIDI_DEBUG(4,printf("midistat_read\n"));
974 mtx_lock(&midistat_lock);
975 if (!midistat_isopen) {
976 mtx_unlock(&midistat_lock);
977 return EBADF;
978 }
979 l = min(buf->uio_resid, sbuf_len(&midistat_sbuf) - midistat_bufptr);
980 err = 0;
981 if (l > 0) {
982 mtx_unlock(&midistat_lock);
983 err = uiomove(sbuf_data(&midistat_sbuf) + midistat_bufptr, l, buf);
984 mtx_lock(&midistat_lock);
985 } else
986 l = 0;
987 midistat_bufptr += l;
988 mtx_unlock(&midistat_lock);
989 return err;
990}
991
992/*
993 * Module library functions
994 */
995
996static int
997midistat_prepare(struct sbuf * s)
998{
999 struct snd_midi *m;
1000
1001 mtx_assert(&midistat_lock, MA_OWNED);
1002
1003 sbuf_printf(s, "FreeBSD Midi Driver (midi2)\n");
1004 if (TAILQ_EMPTY(&midi_devs)) {
1005 sbuf_printf(s, "No devices installed.\n");
1006 sbuf_finish(s);
1007 return sbuf_len(s);
1008 }
1009 sbuf_printf(s, "Installed devices:\n");
1010
1011 TAILQ_FOREACH(m, &midi_devs, link) {
1012 mtx_lock(&m->lock);
1013 sbuf_printf(s, "%s [%d/%d:%s]", m->name, m->unit, m->channel,
1014 MPU_PROVIDER(m, m->cookie));
1015 sbuf_printf(s, "%s", MPU_DESCR(m, m->cookie, midistat_verbose));
1016 sbuf_printf(s, "\n");
1017 mtx_unlock(&m->lock);
1018 }
1019
1020 sbuf_finish(s);
1021 return sbuf_len(s);
1022}
1023
1024#ifdef notdef
1025/*
1026 * Convert IOCTL command to string for debugging
1027 */
1028
1029static char *
1030midi_cmdname(int cmd)
1031{
1032 static struct {
1033 int cmd;
1034 char *name;
1035 } *tab, cmdtab_midiioctl[] = {
1036#define A(x) {x, ## x}
1037 /*
1038 * Once we have some real IOCTLs define, the following will
1039 * be relavant.
1040 *
1041 * A(SNDCTL_MIDI_PRETIME), A(SNDCTL_MIDI_MPUMODE),
1042 * A(SNDCTL_MIDI_MPUCMD), A(SNDCTL_SYNTH_INFO),
1043 * A(SNDCTL_MIDI_INFO), A(SNDCTL_SYNTH_MEMAVL),
1044 * A(SNDCTL_FM_LOAD_INSTR), A(SNDCTL_FM_4OP_ENABLE),
1045 * A(MIOSPASSTHRU), A(MIOGPASSTHRU), A(AIONWRITE),
1046 * A(AIOGSIZE), A(AIOSSIZE), A(AIOGFMT), A(AIOSFMT),
1047 * A(AIOGMIX), A(AIOSMIX), A(AIOSTOP), A(AIOSYNC),
1048 * A(AIOGCAP),
1049 */
1050#undef A
1051 {
1052 -1, "unknown"
1053 },
1054 };
1055
1056 for (tab = cmdtab_midiioctl; tab->cmd != cmd && tab->cmd != -1; tab++)
1057 ;
1058 return tab->name;
1059}
1060#endif /* notdef */
1061
1062/*
1063 * midisynth
1064 */
1065
1066
1067int
1068midisynth_open(void *n, void *arg, int flags)
1069{
1070 struct snd_midi *m = ((struct synth_midi * ) n)->m;
1071 int retval;
1072
1073 MIDI_DEBUG(1,printf("midisynth_open %s %s\n",
1074 flags & FREAD?"M_RX":"", flags & FWRITE?"M_TX":""));
1075
1076 if (m == NULL)
1077 return ENXIO;
1078
1079 mtx_lock(&m->lock);
1080 mtx_lock(&m->qlock);
1081
1082 retval = 0;
1083
1084 if (flags & FREAD) {
1085 if (MIDIQ_SIZE(m->inq) == 0)
1086 retval = ENXIO;
1087 else if (m->flags & M_RX)
1088 retval = EBUSY;
1089 if (retval)
1090 goto err;
1091 }
1092 if (flags & FWRITE) {
1093 if (MIDIQ_SIZE(m->outq) == 0)
1094 retval = ENXIO;
1095 else if (m->flags & M_TX)
1096 retval = EBUSY;
1097 if (retval)
1098 goto err;
1099 }
1100 m->busy++;
1101
1102 /*
1103 * TODO: Consider m->async = 0;
1104 */
1105
1106 if (flags & FREAD) {
1107 m->flags |= M_RX | M_RXEN;
1108 /*
1109 * Only clear the inq, the outq might still have data to drain from
1110 * a previous session
1111 */
1112 MIDIQ_CLEAR(m->inq);
1113 m->rchan = 0;
1114 };
1115
1116 if (flags & FWRITE) {
1117 m->flags |= M_TX;
1118 m->wchan = 0;
1119 }
1120
1121 m->synth_flags = flags & (FREAD | FWRITE);
1122
1123 MPU_CALLBACK(m, m->cookie, m->flags);
1124
1125
1126err: mtx_unlock(&m->qlock);
1127 mtx_unlock(&m->lock);
1128 MIDI_DEBUG(2, printf("midisynth_open: return %d.\n", retval));
1129 return retval;
1130}
1131
1132int
1133midisynth_close(void *n)
1134{
1135 struct snd_midi *m = ((struct synth_midi *)n)->m;
1136 int retval;
1137 int oldflags;
1138
1139 MIDI_DEBUG(1, printf("midisynth_close %s %s\n",
1140 m->synth_flags & FREAD ? "M_RX" : "",
1141 m->synth_flags & FWRITE ? "M_TX" : ""));
1142
1143 if (m == NULL)
1144 return ENXIO;
1145
1146 mtx_lock(&m->lock);
1147 mtx_lock(&m->qlock);
1148
1149 if ( (m->synth_flags & FREAD && !(m->flags & M_RX)) ||
1150 (m->synth_flags & FWRITE && !(m->flags & M_TX)) ) {
1151 retval = ENXIO;
1152 goto err;
1153 }
1154
1155 m->busy--;
1156
1157 oldflags = m->flags;
1158
1159 if (m->synth_flags & FREAD)
1160 m->flags &= ~(M_RX | M_RXEN);
1161 if (m->synth_flags & FWRITE)
1162 m->flags &= ~M_TX;
1163
1164 if( (m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)) )
1165 MPU_CALLBACK(m, m->cookie, m->flags);
1166
1167 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
1168
1169 mtx_unlock(&m->qlock);
1170 mtx_unlock(&m->lock);
1171 retval = 0;
1172err: return retval;
1173}
1174
1175/*
1176 * Always blocking.
1177 */
1178
1179int
1180midisynth_writeraw(void *n, uint8_t *buf, size_t len)
1181{
1182 struct snd_midi *m = ((struct synth_midi *)n)->m;
1183 int retval;
1184 int used;
1185 int i;
1186
1187 MIDI_DEBUG(4, printf("midisynth_writeraw\n"));
1188
1189 retval = 0;
1190
1191 if (m == NULL)
1192 return ENXIO;
1193
1194 mtx_lock(&m->lock);
1195 mtx_lock(&m->qlock);
1196
1197 if (!(m->flags & M_TX))
1198 goto err1;
1199
1200 if (midi_dumpraw)
1201 printf("midi dump: ");
1202
1203 while (len > 0) {
1204 while (MIDIQ_AVAIL(m->outq) == 0) {
1205 if (!(m->flags & M_TXEN)) {
1206 m->flags |= M_TXEN;
1207 MPU_CALLBACK(m, m->cookie, m->flags);
1208 }
1209 mtx_unlock(&m->lock);
1210 m->wchan = 1;
1211 MIDI_DEBUG(3,printf("midisynth_writeraw msleep\n"));
1212 retval = msleep(&m->wchan, &m->qlock,
1213 PCATCH | PDROP, "midi TX", 0);
1214 /*
1215 * We slept, maybe things have changed since last
1216 * dying check
1217 */
1218 if (retval == EINTR)
1219 goto err0;
1220
1221 if (retval)
1222 goto err0;
1223 mtx_lock(&m->lock);
1224 mtx_lock(&m->qlock);
1225 m->wchan = 0;
1226 if (!m->busy)
1227 goto err1;
1228 }
1229
1230 /*
1231 * We are certain than data can be placed on the queue
1232 */
1233
1234 used = MIN(MIDIQ_AVAIL(m->outq), len);
1235 used = MIN(used, MIDI_WSIZE);
1236 MIDI_DEBUG(5,printf("midi_synth: resid %zu len %jd avail %jd\n",
1237 len, (intmax_t)MIDIQ_LEN(m->outq),
1238 (intmax_t)MIDIQ_AVAIL(m->outq)));
1239
1240 if (midi_dumpraw)
1241 for(i=0;i<used;i++) printf("%x ", buf[i]);
1242
1243 MIDIQ_ENQ(m->outq, buf, used);
1244 len -= used;
1245
1246 /*
1247 * Inform the bottom half that data can be written
1248 */
1249 if (!(m->flags & M_TXEN)) {
1250 m->flags |= M_TXEN;
1251 MPU_CALLBACK(m, m->cookie, m->flags);
1252 }
1253 }
1254 /*
1255 * If we Made it here then transfer is good
1256 */
1257 if (midi_dumpraw)
1258 printf("\n");
1259
1260 retval = 0;
1261err1: mtx_unlock(&m->qlock);
1262 mtx_unlock(&m->lock);
1263err0: return retval;
1264}
1265
1266static int
1267midisynth_killnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1268{
1269 u_char c[3];
1270
1271
1272 if (note > 127 || chn > 15)
1273 return (EINVAL);
1274
1275 if (vel > 127)
1276 vel = 127;
1277
1278 if (vel == 64) {
1279 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1280 c[1] = (u_char)note;
1281 c[2] = 0;
1282 } else {
1283 c[0] = 0x80 | (chn & 0x0f); /* Note off. */
1284 c[1] = (u_char)note;
1285 c[2] = (u_char)vel;
1286 }
1287
1288 return midisynth_writeraw(n, c, 3);
1289}
1290
1291static int
1292midisynth_setinstr(void *n, uint8_t chn, uint16_t instr)
1293{
1294 u_char c[2];
1295
1296 if (instr > 127 || chn > 15)
1297 return EINVAL;
1298
1299 c[0] = 0xc0 | (chn & 0x0f); /* Progamme change. */
1300 c[1] = instr + midi_instroff;
1301
1302 return midisynth_writeraw(n, c, 2);
1303}
1304
1305static int
1306midisynth_startnote(void *n, uint8_t chn, uint8_t note, uint8_t vel)
1307{
1308 u_char c[3];
1309
1310 if (note > 127 || chn > 15)
1311 return EINVAL;
1312
1313 if (vel > 127)
1314 vel = 127;
1315
1316 c[0] = 0x90 | (chn & 0x0f); /* Note on. */
1317 c[1] = (u_char)note;
1318 c[2] = (u_char)vel;
1319
1320 return midisynth_writeraw(n, c, 3);
1321}
1322static int
1323midisynth_alloc(void *n, uint8_t chan, uint8_t note)
1324{
1325 return chan;
1326}
1327
1328static int
1329midisynth_controller(void *n, uint8_t chn, uint8_t ctrlnum, uint16_t val)
1330{
1331 u_char c[3];
1332
1333 if (ctrlnum > 127 || chn > 15)
1334 return EINVAL;
1335
1336 c[0] = 0xb0 | (chn & 0x0f); /* Control Message. */
1337 c[1] = ctrlnum;
1338 c[2] = val;
1339 return midisynth_writeraw(n, c, 3);
1340}
1341
1342static int
1343midisynth_bender(void *n, uint8_t chn, uint16_t val)
1344{
1345 u_char c[3];
1346
1347
1348 if (val > 16383 || chn > 15)
1349 return EINVAL;
1350
1351 c[0] = 0xe0 | (chn & 0x0f); /* Pitch bend. */
1352 c[1] = (u_char)val & 0x7f;
1353 c[2] = (u_char)(val >> 7) & 0x7f;
1354
1355 return midisynth_writeraw(n, c, 3);
1356}
1357
1358/*
1359 * Single point of midi destructions.
1360 */
1361static int
1362midi_destroy(struct snd_midi * m, int midiuninit)
1363{
1364
1365 mtx_assert(&midistat_lock, MA_OWNED);
1366 mtx_assert(&m->lock, MA_OWNED);
1367
1368 MIDI_DEBUG(3,printf("midi_destroy\n"));
1369 m->dev->si_drv1 = NULL;
1370 destroy_dev(m->dev);
1371 TAILQ_REMOVE(&midi_devs, m, link);
1372 if (midiuninit)
1373 MPU_UNINIT(m, m->cookie);
1374 free(MIDIQ_BUF(m->inq), M_MIDI);
1375 free(MIDIQ_BUF(m->outq), M_MIDI);
1376 mtx_destroy(&m->qlock);
1377 mtx_destroy(&m->lock);
1378 free(m, M_MIDI);
1379 return 0;
1380}
1381
1382/*
1383 * Load and unload functions, creates the /dev/midistat device
1384 */
1385
1386static int
1387midi_load()
1388{
1389 mtx_init(&midistat_lock, "midistat lock", 0, 0);
1390 TAILQ_INIT(&midi_devs); /* Initialize the queue. */
1391
1392 midistat_dev = make_dev(&midistat_cdevsw,
1393 MIDIMKMINOR(0, MIDI_DEV_MIDICTL, 0),
1394 UID_ROOT, GID_WHEEL, 0666, "midistat");
1395
1396 return 0;
1397}
1398
1399static int
1400midi_unload()
1401{
1402 struct snd_midi *m;
1403 int retval;
1404
1405 MIDI_DEBUG(1,printf("midi_unload()\n"));
1406 retval = EBUSY;
1407 mtx_lock(&midistat_lock);
1408 if (midistat_isopen)
1409 goto exit0;
1410
1411 TAILQ_FOREACH(m, &midi_devs, link) {
1412 mtx_lock(&m->lock);
1413 if (m->busy)
1414 retval = EBUSY;
1415 else
1416 retval = midi_destroy(m, 1);
1417 if (retval)
1418 goto exit1;
1419 }
1420
1421 destroy_dev(midistat_dev);
1422 /*
1423 * Made it here then unload is complete
1424 */
1425 mtx_destroy(&midistat_lock);
1426 return 0;
1427
1428exit1:
1429 mtx_unlock(&m->lock);
1430exit0:
1431 mtx_unlock(&midistat_lock);
1432 if(retval) MIDI_DEBUG(2,printf("midi_unload: failed\n"));
1433 return retval;
1434}
1435
1436extern int seq_modevent(module_t mod, int type, void *data);
1437
1438static int
1439midi_modevent(module_t mod, int type, void *data)
1440{
1441 int retval;
1442
1443 retval = 0;
1444
1445 switch (type) {
1446 case MOD_LOAD:
1447 retval = midi_load();
1448 if (retval == 0)
1449 retval = seq_modevent(mod, type, data);
1450 break;
1451
1452 case MOD_UNLOAD:
1453 retval = midi_unload();
1454 if (retval == 0)
1455 retval = seq_modevent(mod, type, data);
1456 break;
1457
1458 default:
1459 break;
1460 }
1461
1462 return retval;
1463}
1464
1465kobj_t
1466midimapper_addseq(void *arg1, int *unit, void **cookie)
1467{
1468 unit = 0;
1469
1470 return (kobj_t) arg1;
1471}
1472
1473int
1474midimapper_open(void *arg1, void **cookie)
1475{
1476 int retval = 0;
1477 struct snd_midi *m;
1478
1479 mtx_lock(&midistat_lock);
1480
1481 TAILQ_FOREACH(m, &midi_devs, link) {
1482 retval++;
1483 }
1484
1485 mtx_unlock(&midistat_lock);
1486 return retval;
1487}
1488
1489int
1490midimapper_close(void *arg1, void *cookie)
1491{
1492 return 0;
1493}
1494
1495kobj_t
1496midimapper_fetch_synth(void *arg, void *cookie, int unit)
1497{
1498 struct snd_midi *m;
1499 int retval = 0;
1500
1501 mtx_lock(&midistat_lock);
1502
1503 TAILQ_FOREACH(m, &midi_devs, link) {
1504 if (unit == retval) {
1505 mtx_unlock(&midistat_lock);
1506 return (kobj_t)m->synth;
1507 }
1508 retval++;
1509 }
1510
1511 mtx_unlock(&midistat_lock);
1512 return NULL;
1513}
1514
1515DEV_MODULE(midi, midi_modevent, NULL);
1516MODULE_VERSION(midi, 1);