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