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