1 /* $OpenBSD: midi.c,v 1.54 2022/04/06 18:59:27 naddy Exp $ */ 2 3 /* 4 * Copyright (c) 2003, 2004 Alexandre Ratchov 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/fcntl.h> 21 #include <sys/systm.h> 22 #include <sys/ioctl.h> 23 #include <sys/conf.h> 24 #include <sys/poll.h> 25 #include <sys/kernel.h> 26 #include <sys/timeout.h> 27 #include <sys/vnode.h> 28 #include <sys/signalvar.h> 29 #include <sys/device.h> 30 31 #include <dev/midi_if.h> 32 #include <dev/audio_if.h> 33 #include <dev/midivar.h> 34 35 #define IPL_SOFTMIDI IPL_SOFTNET 36 #define DEVNAME(sc) ((sc)->dev.dv_xname) 37 38 int midiopen(dev_t, int, int, struct proc *); 39 int midiclose(dev_t, int, int, struct proc *); 40 int midiread(dev_t, struct uio *, int); 41 int midiwrite(dev_t, struct uio *, int); 42 int midipoll(dev_t, int, struct proc *); 43 int midikqfilter(dev_t, struct knote *); 44 int midiioctl(dev_t, u_long, caddr_t, int, struct proc *); 45 int midiprobe(struct device *, void *, void *); 46 void midiattach(struct device *, struct device *, void *); 47 int mididetach(struct device *, int); 48 int midiprint(void *, const char *); 49 50 void midi_iintr(void *, int); 51 void midi_ointr(void *); 52 void midi_timeout(void *); 53 void midi_out_start(struct midi_softc *); 54 void midi_out_stop(struct midi_softc *); 55 void midi_out_do(struct midi_softc *); 56 void midi_attach(struct midi_softc *, struct device *); 57 58 59 const struct cfattach midi_ca = { 60 sizeof(struct midi_softc), midiprobe, midiattach, mididetach 61 }; 62 63 struct cfdriver midi_cd = { 64 NULL, "midi", DV_DULL 65 }; 66 67 68 void filt_midiwdetach(struct knote *); 69 int filt_midiwrite(struct knote *, long); 70 71 const struct filterops midiwrite_filtops = { 72 .f_flags = FILTEROP_ISFD, 73 .f_attach = NULL, 74 .f_detach = filt_midiwdetach, 75 .f_event = filt_midiwrite, 76 }; 77 78 void filt_midirdetach(struct knote *); 79 int filt_midiread(struct knote *, long); 80 81 const struct filterops midiread_filtops = { 82 .f_flags = FILTEROP_ISFD, 83 .f_attach = NULL, 84 .f_detach = filt_midirdetach, 85 .f_event = filt_midiread, 86 }; 87 88 void 89 midi_buf_wakeup(void *addr) 90 { 91 struct midi_buffer *buf = addr; 92 93 if (buf->blocking) { 94 wakeup(&buf->blocking); 95 buf->blocking = 0; 96 } 97 /* 98 * As long as selwakeup() grabs the KERNEL_LOCK() make sure it is 99 * already held here to avoid lock ordering problems with `audio_lock' 100 */ 101 KERNEL_ASSERT_LOCKED(); 102 mtx_enter(&audio_lock); 103 selwakeup(&buf->sel); 104 mtx_leave(&audio_lock); 105 } 106 107 void 108 midi_iintr(void *addr, int data) 109 { 110 struct midi_softc *sc = (struct midi_softc *)addr; 111 struct midi_buffer *mb = &sc->inbuf; 112 113 MUTEX_ASSERT_LOCKED(&audio_lock); 114 if (!(sc->dev.dv_flags & DVF_ACTIVE) || !(sc->flags & FREAD)) 115 return; 116 117 if (MIDIBUF_ISFULL(mb)) 118 return; /* discard data */ 119 120 MIDIBUF_WRITE(mb, data); 121 122 /* 123 * As long as selwakeup() needs to be protected by the 124 * KERNEL_LOCK() we have to delay the wakeup to another 125 * context to keep the interrupt context KERNEL_LOCK() 126 * free. 127 */ 128 softintr_schedule(sc->inbuf.softintr); 129 } 130 131 int 132 midiread(dev_t dev, struct uio *uio, int ioflag) 133 { 134 struct midi_softc *sc; 135 struct midi_buffer *mb; 136 size_t count; 137 int error; 138 139 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 140 if (sc == NULL) 141 return ENXIO; 142 if (!(sc->flags & FREAD)) { 143 error = ENXIO; 144 goto done; 145 } 146 mb = &sc->inbuf; 147 148 /* if there is no data then sleep (unless IO_NDELAY flag is set) */ 149 error = 0; 150 mtx_enter(&audio_lock); 151 while (MIDIBUF_ISEMPTY(mb)) { 152 if (ioflag & IO_NDELAY) { 153 error = EWOULDBLOCK; 154 goto done_mtx; 155 } 156 sc->inbuf.blocking = 1; 157 error = msleep_nsec(&sc->inbuf.blocking, &audio_lock, 158 PWAIT | PCATCH, "mid_rd", INFSLP); 159 if (!(sc->dev.dv_flags & DVF_ACTIVE)) 160 error = EIO; 161 if (error) 162 goto done_mtx; 163 } 164 165 /* at this stage, there is at least 1 byte */ 166 167 while (uio->uio_resid > 0 && mb->used > 0) { 168 count = MIDIBUF_SIZE - mb->start; 169 if (count > mb->used) 170 count = mb->used; 171 if (count > uio->uio_resid) 172 count = uio->uio_resid; 173 mtx_leave(&audio_lock); 174 error = uiomove(mb->data + mb->start, count, uio); 175 if (error) 176 goto done; 177 mtx_enter(&audio_lock); 178 MIDIBUF_REMOVE(mb, count); 179 } 180 181 done_mtx: 182 mtx_leave(&audio_lock); 183 done: 184 device_unref(&sc->dev); 185 return error; 186 } 187 188 void 189 midi_ointr(void *addr) 190 { 191 struct midi_softc *sc = (struct midi_softc *)addr; 192 struct midi_buffer *mb; 193 194 MUTEX_ASSERT_LOCKED(&audio_lock); 195 if (!(sc->dev.dv_flags & DVF_ACTIVE) || !(sc->flags & FWRITE)) 196 return; 197 198 mb = &sc->outbuf; 199 if (mb->used > 0) { 200 #ifdef MIDI_DEBUG 201 if (!sc->isbusy) { 202 printf("midi_ointr: output must be busy\n"); 203 } 204 #endif 205 midi_out_do(sc); 206 } else if (sc->isbusy) 207 midi_out_stop(sc); 208 } 209 210 void 211 midi_timeout(void *addr) 212 { 213 mtx_enter(&audio_lock); 214 midi_ointr(addr); 215 mtx_leave(&audio_lock); 216 } 217 218 void 219 midi_out_start(struct midi_softc *sc) 220 { 221 if (!sc->isbusy) { 222 sc->isbusy = 1; 223 midi_out_do(sc); 224 } 225 } 226 227 void 228 midi_out_stop(struct midi_softc *sc) 229 { 230 sc->isbusy = 0; 231 232 /* 233 * As long as selwakeup() needs to be protected by the 234 * KERNEL_LOCK() we have to delay the wakeup to another 235 * context to keep the interrupt context KERNEL_LOCK() 236 * free. 237 */ 238 softintr_schedule(sc->outbuf.softintr); 239 } 240 241 void 242 midi_out_do(struct midi_softc *sc) 243 { 244 struct midi_buffer *mb = &sc->outbuf; 245 246 while (mb->used > 0) { 247 if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start])) 248 break; 249 MIDIBUF_REMOVE(mb, 1); 250 if (MIDIBUF_ISEMPTY(mb)) { 251 if (sc->hw_if->flush != NULL) 252 sc->hw_if->flush(sc->hw_hdl); 253 midi_out_stop(sc); 254 return; 255 } 256 } 257 258 if (!(sc->props & MIDI_PROP_OUT_INTR)) { 259 if (MIDIBUF_ISEMPTY(mb)) 260 midi_out_stop(sc); 261 else 262 timeout_add(&sc->timeo, 1); 263 } 264 } 265 266 int 267 midiwrite(dev_t dev, struct uio *uio, int ioflag) 268 { 269 struct midi_softc *sc; 270 struct midi_buffer *mb; 271 size_t count; 272 int error; 273 274 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 275 if (sc == NULL) 276 return ENXIO; 277 if (!(sc->flags & FWRITE)) { 278 error = ENXIO; 279 goto done; 280 } 281 mb = &sc->outbuf; 282 283 /* 284 * If IO_NDELAY flag is set then check if there is enough room 285 * in the buffer to store at least one byte. If not then dont 286 * start the write process. 287 */ 288 error = 0; 289 mtx_enter(&audio_lock); 290 if ((ioflag & IO_NDELAY) && MIDIBUF_ISFULL(mb) && (uio->uio_resid > 0)) { 291 error = EWOULDBLOCK; 292 goto done_mtx; 293 } 294 295 while (uio->uio_resid > 0) { 296 while (MIDIBUF_ISFULL(mb)) { 297 if (ioflag & IO_NDELAY) { 298 /* 299 * At this stage at least one byte is already 300 * moved so we do not return EWOULDBLOCK 301 */ 302 goto done_mtx; 303 } 304 sc->outbuf.blocking = 1; 305 error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, 306 PWAIT | PCATCH, "mid_wr", INFSLP); 307 if (!(sc->dev.dv_flags & DVF_ACTIVE)) 308 error = EIO; 309 if (error) 310 goto done_mtx; 311 } 312 313 count = MIDIBUF_SIZE - MIDIBUF_END(mb); 314 if (count > MIDIBUF_AVAIL(mb)) 315 count = MIDIBUF_AVAIL(mb); 316 if (count > uio->uio_resid) 317 count = uio->uio_resid; 318 mtx_leave(&audio_lock); 319 error = uiomove(mb->data + MIDIBUF_END(mb), count, uio); 320 if (error) 321 goto done; 322 mtx_enter(&audio_lock); 323 mb->used += count; 324 midi_out_start(sc); 325 } 326 327 done_mtx: 328 mtx_leave(&audio_lock); 329 done: 330 device_unref(&sc->dev); 331 return error; 332 } 333 334 int 335 midipoll(dev_t dev, int events, struct proc *p) 336 { 337 struct midi_softc *sc; 338 int revents; 339 340 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 341 if (sc == NULL) 342 return POLLERR; 343 revents = 0; 344 mtx_enter(&audio_lock); 345 if (events & (POLLIN | POLLRDNORM)) { 346 if (!MIDIBUF_ISEMPTY(&sc->inbuf)) 347 revents |= events & (POLLIN | POLLRDNORM); 348 } 349 if (events & (POLLOUT | POLLWRNORM)) { 350 if (!MIDIBUF_ISFULL(&sc->outbuf)) 351 revents |= events & (POLLOUT | POLLWRNORM); 352 } 353 if (revents == 0) { 354 if (events & (POLLIN | POLLRDNORM)) 355 selrecord(p, &sc->inbuf.sel); 356 if (events & (POLLOUT | POLLWRNORM)) 357 selrecord(p, &sc->outbuf.sel); 358 } 359 mtx_leave(&audio_lock); 360 device_unref(&sc->dev); 361 return (revents); 362 } 363 364 int 365 midikqfilter(dev_t dev, struct knote *kn) 366 { 367 struct midi_softc *sc; 368 struct klist *klist; 369 int error; 370 371 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 372 if (sc == NULL) 373 return ENXIO; 374 error = 0; 375 switch (kn->kn_filter) { 376 case EVFILT_READ: 377 klist = &sc->inbuf.sel.si_note; 378 kn->kn_fop = &midiread_filtops; 379 break; 380 case EVFILT_WRITE: 381 klist = &sc->outbuf.sel.si_note; 382 kn->kn_fop = &midiwrite_filtops; 383 break; 384 default: 385 error = EINVAL; 386 goto done; 387 } 388 kn->kn_hook = (void *)sc; 389 390 mtx_enter(&audio_lock); 391 klist_insert_locked(klist, kn); 392 mtx_leave(&audio_lock); 393 done: 394 device_unref(&sc->dev); 395 return error; 396 } 397 398 void 399 filt_midirdetach(struct knote *kn) 400 { 401 struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 402 403 mtx_enter(&audio_lock); 404 klist_remove_locked(&sc->inbuf.sel.si_note, kn); 405 mtx_leave(&audio_lock); 406 } 407 408 int 409 filt_midiread(struct knote *kn, long hint) 410 { 411 struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 412 int retval; 413 414 if ((hint & NOTE_SUBMIT) == 0) 415 mtx_enter(&audio_lock); 416 retval = !MIDIBUF_ISEMPTY(&sc->inbuf); 417 if ((hint & NOTE_SUBMIT) == 0) 418 mtx_leave(&audio_lock); 419 420 return (retval); 421 } 422 423 void 424 filt_midiwdetach(struct knote *kn) 425 { 426 struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 427 428 mtx_enter(&audio_lock); 429 klist_remove_locked(&sc->outbuf.sel.si_note, kn); 430 mtx_leave(&audio_lock); 431 } 432 433 int 434 filt_midiwrite(struct knote *kn, long hint) 435 { 436 struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 437 int retval; 438 439 if ((hint & NOTE_SUBMIT) == 0) 440 mtx_enter(&audio_lock); 441 retval = !MIDIBUF_ISFULL(&sc->outbuf); 442 if ((hint & NOTE_SUBMIT) == 0) 443 mtx_leave(&audio_lock); 444 445 return (retval); 446 } 447 448 int 449 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 450 { 451 struct midi_softc *sc; 452 int error; 453 454 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 455 if (sc == NULL) 456 return ENXIO; 457 error = 0; 458 switch(cmd) { 459 case FIONBIO: 460 /* All handled in the upper FS layer */ 461 break; 462 default: 463 error = ENOTTY; 464 } 465 device_unref(&sc->dev); 466 return error; 467 } 468 469 int 470 midiopen(dev_t dev, int flags, int mode, struct proc *p) 471 { 472 struct midi_softc *sc; 473 int error; 474 475 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 476 if (sc == NULL) 477 return ENXIO; 478 error = 0; 479 if (sc->flags) { 480 error = EBUSY; 481 goto done; 482 } 483 MIDIBUF_INIT(&sc->inbuf); 484 MIDIBUF_INIT(&sc->outbuf); 485 sc->isbusy = 0; 486 sc->inbuf.blocking = sc->outbuf.blocking = 0; 487 sc->flags = flags; 488 error = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc); 489 if (error) 490 sc->flags = 0; 491 done: 492 device_unref(&sc->dev); 493 return error; 494 } 495 496 int 497 midiclose(dev_t dev, int fflag, int devtype, struct proc *p) 498 { 499 struct midi_softc *sc; 500 struct midi_buffer *mb; 501 int error; 502 503 sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 504 if (sc == NULL) 505 return ENXIO; 506 507 /* start draining output buffer */ 508 error = 0; 509 mb = &sc->outbuf; 510 mtx_enter(&audio_lock); 511 if (!MIDIBUF_ISEMPTY(mb)) 512 midi_out_start(sc); 513 while (sc->isbusy) { 514 sc->outbuf.blocking = 1; 515 error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, 516 PWAIT, "mid_dr", SEC_TO_NSEC(5)); 517 if (!(sc->dev.dv_flags & DVF_ACTIVE)) 518 error = EIO; 519 if (error) 520 break; 521 } 522 mtx_leave(&audio_lock); 523 524 /* 525 * some hw_if->close() reset immediately the midi uart 526 * which flushes the internal buffer of the uart device, 527 * so we may lose some (important) data. To avoid this, 528 * sleep 20ms (around 64 bytes) to give the time to the 529 * uart to drain its internal buffers. 530 */ 531 tsleep_nsec(&sc->outbuf.blocking, PWAIT, "mid_cl", MSEC_TO_NSEC(20)); 532 sc->hw_if->close(sc->hw_hdl); 533 sc->flags = 0; 534 device_unref(&sc->dev); 535 return 0; 536 } 537 538 int 539 midiprobe(struct device *parent, void *match, void *aux) 540 { 541 struct audio_attach_args *sa = aux; 542 543 return (sa != NULL && (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0); 544 } 545 546 void 547 midiattach(struct device *parent, struct device *self, void *aux) 548 { 549 struct midi_info mi; 550 struct midi_softc *sc = (struct midi_softc *)self; 551 struct audio_attach_args *sa = (struct audio_attach_args *)aux; 552 const struct midi_hw_if *hwif = sa->hwif; 553 void *hdl = sa->hdl; 554 555 #ifdef DIAGNOSTIC 556 if (hwif == 0 || 557 hwif->open == 0 || 558 hwif->close == 0 || 559 hwif->output == 0 || 560 hwif->getinfo == 0) { 561 printf("%s: missing method\n", DEVNAME(sc)); 562 return; 563 } 564 #endif 565 566 sc->inbuf.softintr = softintr_establish(IPL_SOFTMIDI, 567 midi_buf_wakeup, &sc->inbuf); 568 if (sc->inbuf.softintr == NULL) { 569 printf("%s: can't establish input softintr\n", DEVNAME(sc)); 570 return; 571 } 572 573 sc->outbuf.softintr = softintr_establish(IPL_SOFTMIDI, 574 midi_buf_wakeup, &sc->outbuf); 575 if (sc->outbuf.softintr == NULL) { 576 printf("%s: can't establish output softintr\n", DEVNAME(sc)); 577 softintr_disestablish(sc->inbuf.softintr); 578 return; 579 } 580 581 sc->hw_if = hwif; 582 sc->hw_hdl = hdl; 583 sc->hw_if->getinfo(sc->hw_hdl, &mi); 584 sc->props = mi.props; 585 sc->flags = 0; 586 timeout_set(&sc->timeo, midi_timeout, sc); 587 printf(": <%s>\n", mi.name); 588 } 589 590 int 591 mididetach(struct device *self, int flags) 592 { 593 struct midi_softc *sc = (struct midi_softc *)self; 594 int maj, mn; 595 596 /* locate the major number */ 597 for (maj = 0; maj < nchrdev; maj++) { 598 if (cdevsw[maj].d_open == midiopen) { 599 /* Nuke the vnodes for any open instances (calls close). */ 600 mn = self->dv_unit; 601 vdevgone(maj, mn, mn, VCHR); 602 } 603 } 604 605 /* 606 * The close() method did nothing (device_lookup() returns 607 * NULL), so quickly halt transfers (normally parent is already 608 * gone, and code below is no-op), and wake-up user-land blocked 609 * in read/write/ioctl, which return EIO. 610 */ 611 if (sc->flags) { 612 KERNEL_ASSERT_LOCKED(); 613 if (sc->flags & FREAD) { 614 wakeup(&sc->inbuf.blocking); 615 mtx_enter(&audio_lock); 616 selwakeup(&sc->inbuf.sel); 617 mtx_leave(&audio_lock); 618 } 619 if (sc->flags & FWRITE) { 620 wakeup(&sc->outbuf.blocking); 621 mtx_enter(&audio_lock); 622 selwakeup(&sc->outbuf.sel); 623 mtx_leave(&audio_lock); 624 } 625 sc->hw_if->close(sc->hw_hdl); 626 sc->flags = 0; 627 } 628 629 klist_invalidate(&sc->inbuf.sel.si_note); 630 klist_invalidate(&sc->outbuf.sel.si_note); 631 632 if (sc->inbuf.softintr) 633 softintr_disestablish(sc->inbuf.softintr); 634 if (sc->outbuf.softintr) 635 softintr_disestablish(sc->outbuf.softintr); 636 return 0; 637 } 638 639 int 640 midiprint(void *aux, const char *pnp) 641 { 642 if (pnp) 643 printf("midi at %s", pnp); 644 return (UNCONF); 645 } 646 647 struct device * 648 midi_attach_mi(const struct midi_hw_if *hwif, void *hdl, struct device *dev) 649 { 650 struct audio_attach_args arg; 651 652 arg.type = AUDIODEV_TYPE_MIDI; 653 arg.hwif = hwif; 654 arg.hdl = hdl; 655 return config_found(dev, &arg, midiprint); 656 } 657