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