1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2003 Mathew Kanner
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Lennart Augustsson (augustss@netbsd.org).
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/queue.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/mutex.h>
39 #include <sys/proc.h>
40 #include <sys/signalvar.h>
41 #include <sys/conf.h>
42 #include <sys/selinfo.h>
43 #include <sys/sysctl.h>
44 #include <sys/malloc.h>
45 #include <sys/sx.h>
46 #include <sys/proc.h>
47 #include <sys/fcntl.h>
48 #include <sys/types.h>
49 #include <sys/uio.h>
50 #include <sys/poll.h>
51 #include <sys/sbuf.h>
52 #include <sys/kobj.h>
53 #include <sys/module.h>
54
55 #ifdef HAVE_KERNEL_OPTION_HEADERS
56 #include "opt_snd.h"
57 #endif
58
59 #include <dev/sound/midi/midi.h>
60 #include "mpu_if.h"
61
62 #include <dev/sound/midi/midiq.h>
63 MALLOC_DEFINE(M_MIDI, "midi buffers", "Midi data allocation area");
64
65 #define MIDI_NAMELEN 16
66 struct snd_midi {
67 KOBJ_FIELDS;
68 struct mtx lock; /* Protects all but queues */
69 void *cookie;
70
71 int unit; /* Should only be used in midistat */
72 int channel; /* Should only be used in midistat */
73
74 int busy;
75 int flags; /* File flags */
76 char name[MIDI_NAMELEN];
77 struct mtx qlock; /* Protects inq, outq and flags */
78 MIDIQ_HEAD(, char) inq, outq;
79 int rchan, wchan;
80 struct selinfo rsel, wsel;
81 int hiwat; /* QLEN(outq)>High-water -> disable
82 * writes from userland */
83 struct cdev *dev;
84 TAILQ_ENTRY(snd_midi) link;
85 };
86
87 TAILQ_HEAD(, snd_midi) midi_devs;
88
89 struct sx mstat_lock;
90
91 static d_open_t midi_open;
92 static d_close_t midi_close;
93 static d_ioctl_t midi_ioctl;
94 static d_read_t midi_read;
95 static d_write_t midi_write;
96 static d_poll_t midi_poll;
97
98 static struct cdevsw midi_cdevsw = {
99 .d_version = D_VERSION,
100 .d_open = midi_open,
101 .d_close = midi_close,
102 .d_read = midi_read,
103 .d_write = midi_write,
104 .d_ioctl = midi_ioctl,
105 .d_poll = midi_poll,
106 .d_name = "rmidi",
107 };
108
109 static int midi_destroy(struct snd_midi *, int);
110 static int midi_load(void);
111 static int midi_unload(void);
112
113 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
114 "Midi driver");
115
116 int midi_debug;
117 /* XXX: should this be moved into debug.midi? */
118 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
119
120 #define MIDI_DEBUG(l,a) if(midi_debug>=l) a
121
122 void
midistat_lock(void)123 midistat_lock(void)
124 {
125 sx_xlock(&mstat_lock);
126 }
127
128 void
midistat_unlock(void)129 midistat_unlock(void)
130 {
131 sx_xunlock(&mstat_lock);
132 }
133
134 void
midistat_lockassert(void)135 midistat_lockassert(void)
136 {
137 sx_assert(&mstat_lock, SA_XLOCKED);
138 }
139
140 /*
141 * Register a new rmidi device. cls midi_if interface unit == 0 means
142 * auto-assign new unit number unit != 0 already assigned a unit number, eg.
143 * not the first channel provided by this device. channel, sub-unit
144 * cookie is passed back on MPU calls Typical device drivers will call with
145 * unit=0, channel=1..(number of channels) and cookie=soft_c and won't care
146 * what unit number is used.
147 *
148 * It is an error to call midi_init with an already used unit/channel combo.
149 */
150 struct snd_midi *
midi_init(kobj_class_t cls,int unit,int channel,void * cookie)151 midi_init(kobj_class_t cls, int unit, int channel, void *cookie)
152 {
153 struct snd_midi *m;
154 int i;
155 int inqsize, outqsize;
156 uint8_t *buf;
157
158 MIDI_DEBUG(1, printf("midiinit: unit %d/%d.\n", unit, channel));
159 midistat_lock();
160 /*
161 * Protect against call with existing unit/channel or auto-allocate a
162 * new unit number.
163 */
164 i = -1;
165 TAILQ_FOREACH(m, &midi_devs, link) {
166 mtx_lock(&m->lock);
167 if (unit != 0) {
168 if (m->unit == unit && m->channel == channel) {
169 mtx_unlock(&m->lock);
170 goto err0;
171 }
172 } else {
173 /*
174 * Find a better unit number
175 */
176 if (m->unit > i)
177 i = m->unit;
178 }
179 mtx_unlock(&m->lock);
180 }
181
182 if (unit == 0)
183 unit = i + 1;
184
185 MIDI_DEBUG(1, printf("midiinit #2: unit %d/%d.\n", unit, channel));
186 m = malloc(sizeof(*m), M_MIDI, M_WAITOK | M_ZERO);
187 kobj_init((kobj_t)m, cls);
188 inqsize = MPU_INQSIZE(m, cookie);
189 outqsize = MPU_OUTQSIZE(m, cookie);
190
191 MIDI_DEBUG(1, printf("midiinit queues %d/%d.\n", inqsize, outqsize));
192 if (!inqsize && !outqsize)
193 goto err1;
194
195 mtx_init(&m->lock, "raw midi", NULL, 0);
196 mtx_init(&m->qlock, "q raw midi", NULL, 0);
197
198 mtx_lock(&m->lock);
199 mtx_lock(&m->qlock);
200
201 if (inqsize)
202 buf = malloc(sizeof(uint8_t) * inqsize, M_MIDI, M_NOWAIT);
203 else
204 buf = NULL;
205
206 MIDIQ_INIT(m->inq, buf, inqsize);
207
208 if (outqsize)
209 buf = malloc(sizeof(uint8_t) * outqsize, M_MIDI, M_NOWAIT);
210 else
211 buf = NULL;
212 m->hiwat = outqsize / 2;
213
214 MIDIQ_INIT(m->outq, buf, outqsize);
215
216 if ((inqsize && !MIDIQ_BUF(m->inq)) ||
217 (outqsize && !MIDIQ_BUF(m->outq)))
218 goto err2;
219
220 m->busy = 0;
221 m->flags = 0;
222 m->unit = unit;
223 m->channel = channel;
224 m->cookie = cookie;
225
226 if (MPU_INIT(m, cookie))
227 goto err2;
228
229 mtx_unlock(&m->lock);
230 mtx_unlock(&m->qlock);
231
232 TAILQ_INSERT_TAIL(&midi_devs, m, link);
233
234 midistat_unlock();
235
236 m->dev = make_dev(&midi_cdevsw, unit, UID_ROOT, GID_WHEEL, 0666,
237 "midi%d.%d", unit, channel);
238 m->dev->si_drv1 = m;
239
240 return m;
241
242 err2:
243 mtx_destroy(&m->qlock);
244 mtx_destroy(&m->lock);
245
246 if (MIDIQ_BUF(m->inq))
247 free(MIDIQ_BUF(m->inq), M_MIDI);
248 if (MIDIQ_BUF(m->outq))
249 free(MIDIQ_BUF(m->outq), M_MIDI);
250 err1:
251 free(m, M_MIDI);
252 err0:
253 midistat_unlock();
254 MIDI_DEBUG(1, printf("midi_init ended in error\n"));
255 return NULL;
256 }
257
258 /*
259 * midi_uninit does not call MIDI_UNINIT, as since this is the implementors
260 * entry point. midi_uninit if fact, does not send any methods. A call to
261 * midi_uninit is a defacto promise that you won't manipulate ch anymore
262 */
263 int
midi_uninit(struct snd_midi * m)264 midi_uninit(struct snd_midi *m)
265 {
266 int err;
267
268 err = EBUSY;
269 midistat_lock();
270 mtx_lock(&m->lock);
271 if (m->busy) {
272 if (!(m->rchan || m->wchan))
273 goto err;
274
275 if (m->rchan) {
276 wakeup(&m->rchan);
277 m->rchan = 0;
278 }
279 if (m->wchan) {
280 wakeup(&m->wchan);
281 m->wchan = 0;
282 }
283 }
284 err = midi_destroy(m, 0);
285 if (!err)
286 goto exit;
287
288 err:
289 mtx_unlock(&m->lock);
290 exit:
291 midistat_unlock();
292 return err;
293 }
294
295 #ifdef notdef
296 static int midi_lengths[] = {2, 2, 2, 2, 1, 1, 2, 0};
297
298 #endif /* notdef */
299 /* Number of bytes in a MIDI command */
300 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
301 #define MIDI_ACK 0xfe
302 #define MIDI_IS_STATUS(d) ((d) >= 0x80)
303 #define MIDI_IS_COMMON(d) ((d) >= 0xf0)
304
305 #define MIDI_SYSEX_START 0xF0
306 #define MIDI_SYSEX_END 0xF7
307
308 /*
309 * midi_in: process all data until the queue is full, then discards the rest.
310 * Since midi_in is a state machine, data discards can cause it to get out of
311 * whack. Process as much as possible. It calls, wakeup, selnotify and
312 * psignal at most once.
313 */
314 int
midi_in(struct snd_midi * m,uint8_t * buf,int size)315 midi_in(struct snd_midi *m, uint8_t *buf, int size)
316 {
317 int used;
318
319 MIDI_DEBUG(5, printf("midi_in: m=%p size=%d\n", m, size));
320
321 /*
322 * XXX: locking flub
323 */
324 if (!(m->flags & M_RX))
325 return size;
326
327 used = 0;
328
329 mtx_lock(&m->qlock);
330 MIDI_DEBUG(6, printf("midi_in: len %jd avail %jd\n",
331 (intmax_t)MIDIQ_LEN(m->inq),
332 (intmax_t)MIDIQ_AVAIL(m->inq)));
333 if (MIDIQ_AVAIL(m->inq) > size) {
334 used = size;
335 MIDIQ_ENQ(m->inq, buf, size);
336 } else {
337 MIDI_DEBUG(4, printf("midi_in: Discarding data qu\n"));
338 mtx_unlock(&m->qlock);
339 return 0;
340 }
341 if (m->rchan) {
342 wakeup(&m->rchan);
343 m->rchan = 0;
344 }
345 selwakeup(&m->rsel);
346 mtx_unlock(&m->qlock);
347 return used;
348 }
349
350 /*
351 * midi_out: The only clearer of the M_TXEN flag.
352 */
353 int
midi_out(struct snd_midi * m,uint8_t * buf,int size)354 midi_out(struct snd_midi *m, uint8_t *buf, int size)
355 {
356 int used;
357
358 /*
359 * XXX: locking flub
360 */
361 if (!(m->flags & M_TXEN))
362 return 0;
363
364 MIDI_DEBUG(2, printf("midi_out: %p\n", m));
365 mtx_lock(&m->qlock);
366 used = MIN(size, MIDIQ_LEN(m->outq));
367 MIDI_DEBUG(3, printf("midi_out: used %d\n", used));
368 if (used)
369 MIDIQ_DEQ(m->outq, buf, used);
370 if (MIDIQ_EMPTY(m->outq)) {
371 m->flags &= ~M_TXEN;
372 MPU_CALLBACKP(m, m->cookie, m->flags);
373 }
374 if (used && MIDIQ_AVAIL(m->outq) > m->hiwat) {
375 if (m->wchan) {
376 wakeup(&m->wchan);
377 m->wchan = 0;
378 }
379 selwakeup(&m->wsel);
380 }
381 mtx_unlock(&m->qlock);
382 return used;
383 }
384
385 int
midi_open(struct cdev * i_dev,int flags,int mode,struct thread * td)386 midi_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
387 {
388 struct snd_midi *m = i_dev->si_drv1;
389 int retval;
390
391 MIDI_DEBUG(1, printf("midiopen %p %s %s\n", td,
392 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
393 if (m == NULL)
394 return ENXIO;
395
396 mtx_lock(&m->lock);
397 mtx_lock(&m->qlock);
398
399 retval = 0;
400
401 if (flags & FREAD) {
402 if (MIDIQ_SIZE(m->inq) == 0)
403 retval = ENXIO;
404 else if (m->flags & M_RX)
405 retval = EBUSY;
406 if (retval)
407 goto err;
408 }
409 if (flags & FWRITE) {
410 if (MIDIQ_SIZE(m->outq) == 0)
411 retval = ENXIO;
412 else if (m->flags & M_TX)
413 retval = EBUSY;
414 if (retval)
415 goto err;
416 }
417 m->busy++;
418
419 m->rchan = 0;
420 m->wchan = 0;
421
422 if (flags & FREAD) {
423 m->flags |= M_RX | M_RXEN;
424 /*
425 * Only clear the inq, the outq might still have data to drain
426 * from a previous session
427 */
428 MIDIQ_CLEAR(m->inq);
429 }
430
431 if (flags & FWRITE)
432 m->flags |= M_TX;
433
434 MPU_CALLBACK(m, m->cookie, m->flags);
435
436 MIDI_DEBUG(2, printf("midi_open: opened.\n"));
437
438 err: mtx_unlock(&m->qlock);
439 mtx_unlock(&m->lock);
440 return retval;
441 }
442
443 int
midi_close(struct cdev * i_dev,int flags,int mode,struct thread * td)444 midi_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
445 {
446 struct snd_midi *m = i_dev->si_drv1;
447 int retval;
448 int oldflags;
449
450 MIDI_DEBUG(1, printf("midi_close %p %s %s\n", td,
451 flags & FREAD ? "M_RX" : "", flags & FWRITE ? "M_TX" : ""));
452
453 if (m == NULL)
454 return ENXIO;
455
456 mtx_lock(&m->lock);
457 mtx_lock(&m->qlock);
458
459 if ((flags & FREAD && !(m->flags & M_RX)) ||
460 (flags & FWRITE && !(m->flags & M_TX))) {
461 retval = ENXIO;
462 goto err;
463 }
464 m->busy--;
465
466 oldflags = m->flags;
467
468 if (flags & FREAD)
469 m->flags &= ~(M_RX | M_RXEN);
470 if (flags & FWRITE)
471 m->flags &= ~M_TX;
472
473 if ((m->flags & (M_TXEN | M_RXEN)) != (oldflags & (M_RXEN | M_TXEN)))
474 MPU_CALLBACK(m, m->cookie, m->flags);
475
476 MIDI_DEBUG(1, printf("midi_close: closed, busy = %d.\n", m->busy));
477
478 mtx_unlock(&m->qlock);
479 mtx_unlock(&m->lock);
480 retval = 0;
481 err: return retval;
482 }
483
484 /*
485 * TODO: midi_read, per oss programmer's guide pg. 42 should return as soon
486 * as data is available.
487 */
488 int
midi_read(struct cdev * i_dev,struct uio * uio,int ioflag)489 midi_read(struct cdev *i_dev, struct uio *uio, int ioflag)
490 {
491 #define MIDI_RSIZE 32
492 struct snd_midi *m = i_dev->si_drv1;
493 int retval;
494 int used;
495 char buf[MIDI_RSIZE];
496
497 MIDI_DEBUG(5, printf("midiread: count=%lu\n",
498 (unsigned long)uio->uio_resid));
499
500 retval = EIO;
501
502 if (m == NULL)
503 goto err0;
504
505 mtx_lock(&m->lock);
506 mtx_lock(&m->qlock);
507
508 if (!(m->flags & M_RX))
509 goto err1;
510
511 while (uio->uio_resid > 0) {
512 while (MIDIQ_EMPTY(m->inq)) {
513 retval = EWOULDBLOCK;
514 if (ioflag & O_NONBLOCK)
515 goto err1;
516 mtx_unlock(&m->lock);
517 m->rchan = 1;
518 retval = msleep(&m->rchan, &m->qlock,
519 PCATCH | PDROP, "midi RX", 0);
520 /*
521 * We slept, maybe things have changed since last
522 * dying check
523 */
524 if (retval == EINTR)
525 goto err0;
526 if (m != i_dev->si_drv1)
527 retval = ENXIO;
528 /* if (retval && retval != ERESTART) */
529 if (retval)
530 goto err0;
531 mtx_lock(&m->lock);
532 mtx_lock(&m->qlock);
533 m->rchan = 0;
534 if (!m->busy)
535 goto err1;
536 }
537 MIDI_DEBUG(6, printf("midi_read start\n"));
538 /*
539 * At this point, it is certain that m->inq has data
540 */
541
542 used = MIN(MIDIQ_LEN(m->inq), uio->uio_resid);
543 used = MIN(used, MIDI_RSIZE);
544
545 MIDI_DEBUG(6, printf("midiread: uiomove cc=%d\n", used));
546 MIDIQ_DEQ(m->inq, buf, used);
547 retval = uiomove(buf, used, uio);
548 if (retval)
549 goto err1;
550 }
551
552 /*
553 * If we Made it here then transfer is good
554 */
555 retval = 0;
556 err1: mtx_unlock(&m->qlock);
557 mtx_unlock(&m->lock);
558 err0: MIDI_DEBUG(4, printf("midi_read: ret %d\n", retval));
559 return retval;
560 }
561
562 /*
563 * midi_write: The only setter of M_TXEN
564 */
565
566 int
midi_write(struct cdev * i_dev,struct uio * uio,int ioflag)567 midi_write(struct cdev *i_dev, struct uio *uio, int ioflag)
568 {
569 #define MIDI_WSIZE 32
570 struct snd_midi *m = i_dev->si_drv1;
571 int retval;
572 int used;
573 char buf[MIDI_WSIZE];
574
575 MIDI_DEBUG(4, printf("midi_write\n"));
576 retval = 0;
577 if (m == NULL)
578 goto err0;
579
580 mtx_lock(&m->lock);
581 mtx_lock(&m->qlock);
582
583 if (!(m->flags & M_TX))
584 goto err1;
585
586 while (uio->uio_resid > 0) {
587 while (MIDIQ_AVAIL(m->outq) == 0) {
588 retval = EWOULDBLOCK;
589 if (ioflag & O_NONBLOCK)
590 goto err1;
591 mtx_unlock(&m->lock);
592 m->wchan = 1;
593 MIDI_DEBUG(3, printf("midi_write msleep\n"));
594 retval = msleep(&m->wchan, &m->qlock,
595 PCATCH | PDROP, "midi TX", 0);
596 /*
597 * We slept, maybe things have changed since last
598 * dying check
599 */
600 if (retval == EINTR)
601 goto err0;
602 if (m != i_dev->si_drv1)
603 retval = ENXIO;
604 if (retval)
605 goto err0;
606 mtx_lock(&m->lock);
607 mtx_lock(&m->qlock);
608 m->wchan = 0;
609 if (!m->busy)
610 goto err1;
611 }
612
613 /*
614 * We are certain than data can be placed on the queue
615 */
616
617 used = MIN(MIDIQ_AVAIL(m->outq), uio->uio_resid);
618 used = MIN(used, MIDI_WSIZE);
619 MIDI_DEBUG(5, printf("midiout: resid %zd len %jd avail %jd\n",
620 uio->uio_resid, (intmax_t)MIDIQ_LEN(m->outq),
621 (intmax_t)MIDIQ_AVAIL(m->outq)));
622
623 MIDI_DEBUG(5, printf("midi_write: uiomove cc=%d\n", used));
624 retval = uiomove(buf, used, uio);
625 if (retval)
626 goto err1;
627 MIDIQ_ENQ(m->outq, buf, used);
628 /*
629 * Inform the bottom half that data can be written
630 */
631 if (!(m->flags & M_TXEN)) {
632 m->flags |= M_TXEN;
633 MPU_CALLBACK(m, m->cookie, m->flags);
634 }
635 }
636 /*
637 * If we Made it here then transfer is good
638 */
639 retval = 0;
640 err1: mtx_unlock(&m->qlock);
641 mtx_unlock(&m->lock);
642 err0: return retval;
643 }
644
645 int
midi_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)646 midi_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
647 struct thread *td)
648 {
649 return ENXIO;
650 }
651
652 int
midi_poll(struct cdev * i_dev,int events,struct thread * td)653 midi_poll(struct cdev *i_dev, int events, struct thread *td)
654 {
655 struct snd_midi *m = i_dev->si_drv1;
656 int revents;
657
658 if (m == NULL)
659 return 0;
660
661 revents = 0;
662
663 mtx_lock(&m->lock);
664 mtx_lock(&m->qlock);
665
666 if (events & (POLLIN | POLLRDNORM))
667 if (!MIDIQ_EMPTY(m->inq))
668 events |= events & (POLLIN | POLLRDNORM);
669
670 if (events & (POLLOUT | POLLWRNORM))
671 if (MIDIQ_AVAIL(m->outq) < m->hiwat)
672 events |= events & (POLLOUT | POLLWRNORM);
673
674 if (revents == 0) {
675 if (events & (POLLIN | POLLRDNORM))
676 selrecord(td, &m->rsel);
677
678 if (events & (POLLOUT | POLLWRNORM))
679 selrecord(td, &m->wsel);
680 }
681 mtx_unlock(&m->lock);
682 mtx_unlock(&m->qlock);
683
684 return (revents);
685 }
686
687 /*
688 * Single point of midi destructions.
689 */
690 static int
midi_destroy(struct snd_midi * m,int midiuninit)691 midi_destroy(struct snd_midi *m, int midiuninit)
692 {
693 midistat_lockassert();
694 mtx_assert(&m->lock, MA_OWNED);
695
696 MIDI_DEBUG(3, printf("midi_destroy\n"));
697 m->dev->si_drv1 = NULL;
698 mtx_unlock(&m->lock); /* XXX */
699 destroy_dev(m->dev);
700 TAILQ_REMOVE(&midi_devs, m, link);
701 if (midiuninit)
702 MPU_UNINIT(m, m->cookie);
703 free(MIDIQ_BUF(m->inq), M_MIDI);
704 free(MIDIQ_BUF(m->outq), M_MIDI);
705 mtx_destroy(&m->qlock);
706 mtx_destroy(&m->lock);
707 free(m, M_MIDI);
708 return 0;
709 }
710
711 static int
midi_load(void)712 midi_load(void)
713 {
714 sx_init(&mstat_lock, "midistat lock");
715 TAILQ_INIT(&midi_devs);
716
717 return 0;
718 }
719
720 static int
midi_unload(void)721 midi_unload(void)
722 {
723 struct snd_midi *m, *tmp;
724 int retval;
725
726 MIDI_DEBUG(1, printf("midi_unload()\n"));
727 retval = EBUSY;
728 midistat_lock();
729 TAILQ_FOREACH_SAFE(m, &midi_devs, link, tmp) {
730 mtx_lock(&m->lock);
731 if (m->busy)
732 retval = EBUSY;
733 else
734 retval = midi_destroy(m, 1);
735 if (retval)
736 goto exit;
737 }
738 midistat_unlock();
739
740 sx_destroy(&mstat_lock);
741 return 0;
742
743 exit:
744 mtx_unlock(&m->lock);
745 midistat_unlock();
746 if (retval)
747 MIDI_DEBUG(2, printf("midi_unload: failed\n"));
748 return retval;
749 }
750
751 static int
midi_modevent(module_t mod,int type,void * data)752 midi_modevent(module_t mod, int type, void *data)
753 {
754 int retval;
755
756 retval = 0;
757
758 switch (type) {
759 case MOD_LOAD:
760 retval = midi_load();
761 break;
762
763 case MOD_UNLOAD:
764 retval = midi_unload();
765 break;
766
767 default:
768 break;
769 }
770
771 return retval;
772 }
773
774 DEV_MODULE(midi, midi_modevent, NULL);
775 MODULE_VERSION(midi, 1);
776