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 123 midistat_lock(void) 124 { 125 sx_xlock(&mstat_lock); 126 } 127 128 void 129 midistat_unlock(void) 130 { 131 sx_xunlock(&mstat_lock); 132 } 133 134 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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