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