1*b9ae17a0Sguenther /* $OpenBSD: midi.c,v 1.58 2024/12/30 02:46:00 guenther Exp $ */ 2d1b5c3f8Sbrad 3081bdb75Sderaadt /* 4081bdb75Sderaadt * Copyright (c) 2003, 2004 Alexandre Ratchov 5081bdb75Sderaadt * 6081bdb75Sderaadt * Permission to use, copy, modify, and distribute this software for any 7081bdb75Sderaadt * purpose with or without fee is hereby granted, provided that the above 8081bdb75Sderaadt * copyright notice and this permission notice appear in all copies. 9081bdb75Sderaadt * 10081bdb75Sderaadt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11081bdb75Sderaadt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12081bdb75Sderaadt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13081bdb75Sderaadt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14081bdb75Sderaadt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15081bdb75Sderaadt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16081bdb75Sderaadt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17081bdb75Sderaadt */ 185daee67fSniklas 19081bdb75Sderaadt #include <sys/param.h> 20081bdb75Sderaadt #include <sys/fcntl.h> 21081bdb75Sderaadt #include <sys/systm.h> 22081bdb75Sderaadt #include <sys/ioctl.h> 23081bdb75Sderaadt #include <sys/conf.h> 24081bdb75Sderaadt #include <sys/kernel.h> 25081bdb75Sderaadt #include <sys/timeout.h> 26081bdb75Sderaadt #include <sys/vnode.h> 27081bdb75Sderaadt #include <sys/signalvar.h> 28081bdb75Sderaadt #include <sys/device.h> 295daee67fSniklas 30081bdb75Sderaadt #include <dev/midi_if.h> 31081bdb75Sderaadt #include <dev/audio_if.h> 32081bdb75Sderaadt #include <dev/midivar.h> 335daee67fSniklas 3402e0ccc4Sratchov #define DEVNAME(sc) ((sc)->dev.dv_xname) 356df90749Sjsg 36081bdb75Sderaadt int midiopen(dev_t, int, int, struct proc *); 37081bdb75Sderaadt int midiclose(dev_t, int, int, struct proc *); 38081bdb75Sderaadt int midiread(dev_t, struct uio *, int); 39081bdb75Sderaadt int midiwrite(dev_t, struct uio *, int); 4095f33846Snicm int midikqfilter(dev_t, struct knote *); 41081bdb75Sderaadt int midiioctl(dev_t, u_long, caddr_t, int, struct proc *); 42c4071fd1Smillert int midiprobe(struct device *, void *, void *); 43c4071fd1Smillert void midiattach(struct device *, struct device *, void *); 44081bdb75Sderaadt int mididetach(struct device *, int); 45081bdb75Sderaadt int midiprint(void *, const char *); 46081bdb75Sderaadt 47081bdb75Sderaadt void midi_iintr(void *, int); 48081bdb75Sderaadt void midi_ointr(void *); 49886882aaSratchov void midi_timeout(void *); 50081bdb75Sderaadt void midi_out_start(struct midi_softc *); 51081bdb75Sderaadt void midi_out_stop(struct midi_softc *); 52081bdb75Sderaadt void midi_out_do(struct midi_softc *); 53081bdb75Sderaadt 54081bdb75Sderaadt 55471aeecfSnaddy const struct cfattach midi_ca = { 56081bdb75Sderaadt sizeof(struct midi_softc), midiprobe, midiattach, mididetach 575daee67fSniklas }; 585daee67fSniklas 595daee67fSniklas struct cfdriver midi_cd = { 605daee67fSniklas NULL, "midi", DV_DULL 615daee67fSniklas }; 625daee67fSniklas 635daee67fSniklas 6495f33846Snicm void filt_midiwdetach(struct knote *); 6595f33846Snicm int filt_midiwrite(struct knote *, long); 66cedac2f9Smvs int filt_midimodify(struct kevent *, struct knote *); 67cedac2f9Smvs int filt_midiprocess(struct knote *, struct kevent *); 6895f33846Snicm 6994321eb4Svisa const struct filterops midiwrite_filtops = { 70cedac2f9Smvs .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 7194321eb4Svisa .f_attach = NULL, 7294321eb4Svisa .f_detach = filt_midiwdetach, 7394321eb4Svisa .f_event = filt_midiwrite, 74cedac2f9Smvs .f_modify = filt_midimodify, 75cedac2f9Smvs .f_process = filt_midiprocess, 7695f33846Snicm }; 7795f33846Snicm 7895f33846Snicm void filt_midirdetach(struct knote *); 7995f33846Snicm int filt_midiread(struct knote *, long); 8095f33846Snicm 8194321eb4Svisa const struct filterops midiread_filtops = { 82cedac2f9Smvs .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 8394321eb4Svisa .f_attach = NULL, 8494321eb4Svisa .f_detach = filt_midirdetach, 8594321eb4Svisa .f_event = filt_midiread, 86cedac2f9Smvs .f_modify = filt_midimodify, 87cedac2f9Smvs .f_process = filt_midiprocess, 8895f33846Snicm }; 8995f33846Snicm 905daee67fSniklas void 91cedac2f9Smvs midi_buf_wakeup(struct midi_buffer *buf) 9202e0ccc4Sratchov { 9302e0ccc4Sratchov if (buf->blocking) { 9402e0ccc4Sratchov wakeup(&buf->blocking); 9502e0ccc4Sratchov buf->blocking = 0; 9602e0ccc4Sratchov } 97cedac2f9Smvs knote_locked(&buf->klist, 0); 9802e0ccc4Sratchov } 9902e0ccc4Sratchov 10002e0ccc4Sratchov void 101081bdb75Sderaadt midi_iintr(void *addr, int data) 1025daee67fSniklas { 103081bdb75Sderaadt struct midi_softc *sc = (struct midi_softc *)addr; 1045daee67fSniklas struct midi_buffer *mb = &sc->inbuf; 1055daee67fSniklas 106d0b9e3b5Sratchov MUTEX_ASSERT_LOCKED(&audio_lock); 107d0b9e3b5Sratchov if (!(sc->dev.dv_flags & DVF_ACTIVE) || !(sc->flags & FREAD)) 108066545b4Sratchov return; 1095daee67fSniklas 110081bdb75Sderaadt if (MIDIBUF_ISFULL(mb)) 111081bdb75Sderaadt return; /* discard data */ 11295f33846Snicm 11395f33846Snicm MIDIBUF_WRITE(mb, data); 11402e0ccc4Sratchov 115cedac2f9Smvs midi_buf_wakeup(mb); 1165c8953a5Sjsg } 1175daee67fSniklas 1185daee67fSniklas int 119081bdb75Sderaadt midiread(dev_t dev, struct uio *uio, int ioflag) 1205daee67fSniklas { 121d0b9e3b5Sratchov struct midi_softc *sc; 122f14e0e78Sjsg struct midi_buffer *mb; 12311c52440Sratchov size_t count; 124886882aaSratchov int error; 1255daee67fSniklas 126d0b9e3b5Sratchov sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 127d0b9e3b5Sratchov if (sc == NULL) 128081bdb75Sderaadt return ENXIO; 129d0b9e3b5Sratchov if (!(sc->flags & FREAD)) { 130d0b9e3b5Sratchov error = ENXIO; 131d0b9e3b5Sratchov goto done; 132d0b9e3b5Sratchov } 133f14e0e78Sjsg mb = &sc->inbuf; 1345daee67fSniklas 135081bdb75Sderaadt /* if there is no data then sleep (unless IO_NDELAY flag is set) */ 136d0b9e3b5Sratchov error = 0; 137886882aaSratchov mtx_enter(&audio_lock); 138081bdb75Sderaadt while (MIDIBUF_ISEMPTY(mb)) { 1395daee67fSniklas if (ioflag & IO_NDELAY) { 140d0b9e3b5Sratchov error = EWOULDBLOCK; 141e6c232e8Sratchov goto done_mtx; 1425daee67fSniklas } 14302e0ccc4Sratchov sc->inbuf.blocking = 1; 14402e0ccc4Sratchov error = msleep_nsec(&sc->inbuf.blocking, &audio_lock, 14502e0ccc4Sratchov PWAIT | PCATCH, "mid_rd", INFSLP); 146d0b9e3b5Sratchov if (!(sc->dev.dv_flags & DVF_ACTIVE)) 147d0b9e3b5Sratchov error = EIO; 148e6c232e8Sratchov if (error) 149e6c232e8Sratchov goto done_mtx; 1505daee67fSniklas } 151081bdb75Sderaadt 152081bdb75Sderaadt /* at this stage, there is at least 1 byte */ 153081bdb75Sderaadt 154081bdb75Sderaadt while (uio->uio_resid > 0 && mb->used > 0) { 155081bdb75Sderaadt count = MIDIBUF_SIZE - mb->start; 156081bdb75Sderaadt if (count > mb->used) 157081bdb75Sderaadt count = mb->used; 158081bdb75Sderaadt if (count > uio->uio_resid) 159081bdb75Sderaadt count = uio->uio_resid; 160886882aaSratchov mtx_leave(&audio_lock); 16111c52440Sratchov error = uiomove(mb->data + mb->start, count, uio); 1624ac461caSratchov if (error) 163d0b9e3b5Sratchov goto done; 1644ac461caSratchov mtx_enter(&audio_lock); 165081bdb75Sderaadt MIDIBUF_REMOVE(mb, count); 166081bdb75Sderaadt } 167e6c232e8Sratchov 168e6c232e8Sratchov done_mtx: 169886882aaSratchov mtx_leave(&audio_lock); 170d0b9e3b5Sratchov done: 171d0b9e3b5Sratchov device_unref(&sc->dev); 172d0b9e3b5Sratchov return error; 173081bdb75Sderaadt } 174081bdb75Sderaadt 175081bdb75Sderaadt void 176081bdb75Sderaadt midi_ointr(void *addr) 177081bdb75Sderaadt { 178081bdb75Sderaadt struct midi_softc *sc = (struct midi_softc *)addr; 179081bdb75Sderaadt struct midi_buffer *mb; 180081bdb75Sderaadt 181886882aaSratchov MUTEX_ASSERT_LOCKED(&audio_lock); 182d0b9e3b5Sratchov if (!(sc->dev.dv_flags & DVF_ACTIVE) || !(sc->flags & FWRITE)) 183d0b9e3b5Sratchov return; 184d0b9e3b5Sratchov 185081bdb75Sderaadt mb = &sc->outbuf; 186913ced02Sratchov if (mb->used > 0) { 187913ced02Sratchov #ifdef MIDI_DEBUG 188913ced02Sratchov if (!sc->isbusy) { 189913ced02Sratchov printf("midi_ointr: output must be busy\n"); 190913ced02Sratchov } 191913ced02Sratchov #endif 192913ced02Sratchov midi_out_do(sc); 193913ced02Sratchov } else if (sc->isbusy) 194081bdb75Sderaadt midi_out_stop(sc); 1955daee67fSniklas } 196081bdb75Sderaadt 197886882aaSratchov void 198886882aaSratchov midi_timeout(void *addr) 199886882aaSratchov { 200886882aaSratchov mtx_enter(&audio_lock); 201886882aaSratchov midi_ointr(addr); 202886882aaSratchov mtx_leave(&audio_lock); 203886882aaSratchov } 204081bdb75Sderaadt 205081bdb75Sderaadt void 206081bdb75Sderaadt midi_out_start(struct midi_softc *sc) 207081bdb75Sderaadt { 208081bdb75Sderaadt if (!sc->isbusy) { 209081bdb75Sderaadt sc->isbusy = 1; 210081bdb75Sderaadt midi_out_do(sc); 211081bdb75Sderaadt } 2125daee67fSniklas } 2135daee67fSniklas 2145daee67fSniklas void 215081bdb75Sderaadt midi_out_stop(struct midi_softc *sc) 2165daee67fSniklas { 217081bdb75Sderaadt sc->isbusy = 0; 218cedac2f9Smvs midi_buf_wakeup(&sc->outbuf); 2195daee67fSniklas } 2205daee67fSniklas 221081bdb75Sderaadt void 222081bdb75Sderaadt midi_out_do(struct midi_softc *sc) 2235daee67fSniklas { 2245daee67fSniklas struct midi_buffer *mb = &sc->outbuf; 2255daee67fSniklas 226f3db5e0dSratchov while (mb->used > 0) { 227f3db5e0dSratchov if (!sc->hw_if->output(sc->hw_hdl, mb->data[mb->start])) 2285daee67fSniklas break; 2296df90749Sjsg MIDIBUF_REMOVE(mb, 1); 230081bdb75Sderaadt if (MIDIBUF_ISEMPTY(mb)) { 2316df90749Sjsg if (sc->hw_if->flush != NULL) 2326df90749Sjsg sc->hw_if->flush(sc->hw_hdl); 233081bdb75Sderaadt midi_out_stop(sc); 234081bdb75Sderaadt return; 235081bdb75Sderaadt } 2365daee67fSniklas } 237081bdb75Sderaadt 238081bdb75Sderaadt if (!(sc->props & MIDI_PROP_OUT_INTR)) { 239081bdb75Sderaadt if (MIDIBUF_ISEMPTY(mb)) 240081bdb75Sderaadt midi_out_stop(sc); 241588907faSderaadt else 242f3db5e0dSratchov timeout_add(&sc->timeo, 1); 2435daee67fSniklas } 244081bdb75Sderaadt } 245081bdb75Sderaadt 2465daee67fSniklas int 247081bdb75Sderaadt midiwrite(dev_t dev, struct uio *uio, int ioflag) 2485daee67fSniklas { 249d0b9e3b5Sratchov struct midi_softc *sc; 250f14e0e78Sjsg struct midi_buffer *mb; 25111c52440Sratchov size_t count; 252886882aaSratchov int error; 2535daee67fSniklas 254d0b9e3b5Sratchov sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 255d0b9e3b5Sratchov if (sc == NULL) 256081bdb75Sderaadt return ENXIO; 257d0b9e3b5Sratchov if (!(sc->flags & FWRITE)) { 258d0b9e3b5Sratchov error = ENXIO; 259d0b9e3b5Sratchov goto done; 260d0b9e3b5Sratchov } 261f14e0e78Sjsg mb = &sc->outbuf; 2625daee67fSniklas 263081bdb75Sderaadt /* 264081bdb75Sderaadt * If IO_NDELAY flag is set then check if there is enough room 265081bdb75Sderaadt * in the buffer to store at least one byte. If not then dont 266081bdb75Sderaadt * start the write process. 267081bdb75Sderaadt */ 268d0b9e3b5Sratchov error = 0; 2694ac461caSratchov mtx_enter(&audio_lock); 2704ac461caSratchov if ((ioflag & IO_NDELAY) && MIDIBUF_ISFULL(mb) && (uio->uio_resid > 0)) { 271d0b9e3b5Sratchov error = EWOULDBLOCK; 272e6c232e8Sratchov goto done_mtx; 2734ac461caSratchov } 274081bdb75Sderaadt 275081bdb75Sderaadt while (uio->uio_resid > 0) { 276081bdb75Sderaadt while (MIDIBUF_ISFULL(mb)) { 277081bdb75Sderaadt if (ioflag & IO_NDELAY) { 278081bdb75Sderaadt /* 279081bdb75Sderaadt * At this stage at least one byte is already 280081bdb75Sderaadt * moved so we do not return EWOULDBLOCK 281081bdb75Sderaadt */ 282e6c232e8Sratchov goto done_mtx; 283081bdb75Sderaadt } 28402e0ccc4Sratchov sc->outbuf.blocking = 1; 28502e0ccc4Sratchov error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, 286a3a67300Scheloha PWAIT | PCATCH, "mid_wr", INFSLP); 287d0b9e3b5Sratchov if (!(sc->dev.dv_flags & DVF_ACTIVE)) 288d0b9e3b5Sratchov error = EIO; 289e6c232e8Sratchov if (error) 290e6c232e8Sratchov goto done_mtx; 291081bdb75Sderaadt } 292081bdb75Sderaadt 293081bdb75Sderaadt count = MIDIBUF_SIZE - MIDIBUF_END(mb); 294081bdb75Sderaadt if (count > MIDIBUF_AVAIL(mb)) 295081bdb75Sderaadt count = MIDIBUF_AVAIL(mb); 296081bdb75Sderaadt if (count > uio->uio_resid) 297081bdb75Sderaadt count = uio->uio_resid; 298886882aaSratchov mtx_leave(&audio_lock); 29911c52440Sratchov error = uiomove(mb->data + MIDIBUF_END(mb), count, uio); 3004ac461caSratchov if (error) 301d0b9e3b5Sratchov goto done; 3024ac461caSratchov mtx_enter(&audio_lock); 303081bdb75Sderaadt mb->used += count; 304081bdb75Sderaadt midi_out_start(sc); 305081bdb75Sderaadt } 306e6c232e8Sratchov 307e6c232e8Sratchov done_mtx: 3084ac461caSratchov mtx_leave(&audio_lock); 309d0b9e3b5Sratchov done: 310d0b9e3b5Sratchov device_unref(&sc->dev); 311d0b9e3b5Sratchov return error; 312081bdb75Sderaadt } 313081bdb75Sderaadt 314081bdb75Sderaadt int 31595f33846Snicm midikqfilter(dev_t dev, struct knote *kn) 31695f33846Snicm { 317d0b9e3b5Sratchov struct midi_softc *sc; 31895f33846Snicm struct klist *klist; 319d0b9e3b5Sratchov int error; 32095f33846Snicm 321d0b9e3b5Sratchov sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 322d0b9e3b5Sratchov if (sc == NULL) 323d0b9e3b5Sratchov return ENXIO; 324d0b9e3b5Sratchov error = 0; 32595f33846Snicm switch (kn->kn_filter) { 32695f33846Snicm case EVFILT_READ: 327cedac2f9Smvs klist = &sc->inbuf.klist; 32895f33846Snicm kn->kn_fop = &midiread_filtops; 32995f33846Snicm break; 33095f33846Snicm case EVFILT_WRITE: 331cedac2f9Smvs klist = &sc->outbuf.klist; 33295f33846Snicm kn->kn_fop = &midiwrite_filtops; 33395f33846Snicm break; 33495f33846Snicm default: 335d0b9e3b5Sratchov error = EINVAL; 336d0b9e3b5Sratchov goto done; 33795f33846Snicm } 33895f33846Snicm kn->kn_hook = (void *)sc; 33995f33846Snicm 340cedac2f9Smvs klist_insert(klist, kn); 341d0b9e3b5Sratchov done: 342d0b9e3b5Sratchov device_unref(&sc->dev); 343d0b9e3b5Sratchov return error; 34495f33846Snicm } 34595f33846Snicm 34695f33846Snicm void 34795f33846Snicm filt_midirdetach(struct knote *kn) 34895f33846Snicm { 34995f33846Snicm struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 35095f33846Snicm 351cedac2f9Smvs klist_remove(&sc->inbuf.klist, kn); 35295f33846Snicm } 35395f33846Snicm 35495f33846Snicm int 35595f33846Snicm filt_midiread(struct knote *kn, long hint) 35695f33846Snicm { 35795f33846Snicm struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 35895f33846Snicm 359cedac2f9Smvs return (!MIDIBUF_ISEMPTY(&sc->inbuf)); 36095f33846Snicm } 36195f33846Snicm 36295f33846Snicm void 36395f33846Snicm filt_midiwdetach(struct knote *kn) 36495f33846Snicm { 36595f33846Snicm struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 36695f33846Snicm 367cedac2f9Smvs klist_remove(&sc->outbuf.klist, kn); 36895f33846Snicm } 36995f33846Snicm 37095f33846Snicm int 37195f33846Snicm filt_midiwrite(struct knote *kn, long hint) 37295f33846Snicm { 37395f33846Snicm struct midi_softc *sc = (struct midi_softc *)kn->kn_hook; 37495f33846Snicm 375cedac2f9Smvs return (!MIDIBUF_ISFULL(&sc->outbuf)); 376cedac2f9Smvs } 377cedac2f9Smvs 378cedac2f9Smvs int 379cedac2f9Smvs filt_midimodify(struct kevent *kev, struct knote *kn) 380cedac2f9Smvs { 381cedac2f9Smvs int active; 382cedac2f9Smvs 383886882aaSratchov mtx_enter(&audio_lock); 384cedac2f9Smvs active = knote_modify(kev, kn); 385886882aaSratchov mtx_leave(&audio_lock); 38695f33846Snicm 387cedac2f9Smvs return active; 388cedac2f9Smvs } 389cedac2f9Smvs 390cedac2f9Smvs int 391cedac2f9Smvs filt_midiprocess(struct knote *kn, struct kevent *kev) 392cedac2f9Smvs { 393cedac2f9Smvs int active; 394cedac2f9Smvs 395cedac2f9Smvs mtx_enter(&audio_lock); 396cedac2f9Smvs active = knote_process(kn, kev); 397cedac2f9Smvs mtx_leave(&audio_lock); 398cedac2f9Smvs 399cedac2f9Smvs return active; 40095f33846Snicm } 40195f33846Snicm 40295f33846Snicm int 403081bdb75Sderaadt midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 404081bdb75Sderaadt { 405d0b9e3b5Sratchov struct midi_softc *sc; 406d0b9e3b5Sratchov int error; 407081bdb75Sderaadt 408d0b9e3b5Sratchov sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 409d0b9e3b5Sratchov if (sc == NULL) 410d0b9e3b5Sratchov return ENXIO; 411d0b9e3b5Sratchov error = 0; 412081bdb75Sderaadt switch(cmd) { 413081bdb75Sderaadt default: 414d0b9e3b5Sratchov error = ENOTTY; 415081bdb75Sderaadt } 416d0b9e3b5Sratchov device_unref(&sc->dev); 417d0b9e3b5Sratchov return error; 418081bdb75Sderaadt } 419081bdb75Sderaadt 420081bdb75Sderaadt int 421081bdb75Sderaadt midiopen(dev_t dev, int flags, int mode, struct proc *p) 422081bdb75Sderaadt { 423081bdb75Sderaadt struct midi_softc *sc; 424d0b9e3b5Sratchov int error; 425081bdb75Sderaadt 426d0b9e3b5Sratchov sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 427d0b9e3b5Sratchov if (sc == NULL) 428081bdb75Sderaadt return ENXIO; 429d0b9e3b5Sratchov error = 0; 430d0b9e3b5Sratchov if (sc->flags) { 431d0b9e3b5Sratchov error = EBUSY; 432d0b9e3b5Sratchov goto done; 433d0b9e3b5Sratchov } 434081bdb75Sderaadt MIDIBUF_INIT(&sc->inbuf); 435081bdb75Sderaadt MIDIBUF_INIT(&sc->outbuf); 436081bdb75Sderaadt sc->isbusy = 0; 43702e0ccc4Sratchov sc->inbuf.blocking = sc->outbuf.blocking = 0; 438081bdb75Sderaadt sc->flags = flags; 439d0b9e3b5Sratchov error = sc->hw_if->open(sc->hw_hdl, flags, midi_iintr, midi_ointr, sc); 440d0b9e3b5Sratchov if (error) 441c8d03e3aSratchov sc->flags = 0; 442d0b9e3b5Sratchov done: 443d0b9e3b5Sratchov device_unref(&sc->dev); 444d0b9e3b5Sratchov return error; 445081bdb75Sderaadt } 446081bdb75Sderaadt 447081bdb75Sderaadt int 448081bdb75Sderaadt midiclose(dev_t dev, int fflag, int devtype, struct proc *p) 449081bdb75Sderaadt { 450d0b9e3b5Sratchov struct midi_softc *sc; 451081bdb75Sderaadt struct midi_buffer *mb; 452081bdb75Sderaadt int error; 453081bdb75Sderaadt 454d0b9e3b5Sratchov sc = (struct midi_softc *)device_lookup(&midi_cd, minor(dev)); 455d0b9e3b5Sratchov if (sc == NULL) 456d0b9e3b5Sratchov return ENXIO; 457d0b9e3b5Sratchov 458081bdb75Sderaadt /* start draining output buffer */ 459d0b9e3b5Sratchov error = 0; 460d0b9e3b5Sratchov mb = &sc->outbuf; 461886882aaSratchov mtx_enter(&audio_lock); 462081bdb75Sderaadt if (!MIDIBUF_ISEMPTY(mb)) 463081bdb75Sderaadt midi_out_start(sc); 464081bdb75Sderaadt while (sc->isbusy) { 46502e0ccc4Sratchov sc->outbuf.blocking = 1; 46602e0ccc4Sratchov error = msleep_nsec(&sc->outbuf.blocking, &audio_lock, 467a3a67300Scheloha PWAIT, "mid_dr", SEC_TO_NSEC(5)); 468d0b9e3b5Sratchov if (!(sc->dev.dv_flags & DVF_ACTIVE)) 469d0b9e3b5Sratchov error = EIO; 470d0b9e3b5Sratchov if (error) 471081bdb75Sderaadt break; 472081bdb75Sderaadt } 473886882aaSratchov mtx_leave(&audio_lock); 474081bdb75Sderaadt 475081bdb75Sderaadt /* 476081bdb75Sderaadt * some hw_if->close() reset immediately the midi uart 477081bdb75Sderaadt * which flushes the internal buffer of the uart device, 478f3db5e0dSratchov * so we may lose some (important) data. To avoid this, 479f3db5e0dSratchov * sleep 20ms (around 64 bytes) to give the time to the 480f3db5e0dSratchov * uart to drain its internal buffers. 481081bdb75Sderaadt */ 48202e0ccc4Sratchov tsleep_nsec(&sc->outbuf.blocking, PWAIT, "mid_cl", MSEC_TO_NSEC(20)); 483081bdb75Sderaadt sc->hw_if->close(sc->hw_hdl); 484c8d03e3aSratchov sc->flags = 0; 485d0b9e3b5Sratchov device_unref(&sc->dev); 486081bdb75Sderaadt return 0; 487081bdb75Sderaadt } 488081bdb75Sderaadt 489081bdb75Sderaadt int 490081bdb75Sderaadt midiprobe(struct device *parent, void *match, void *aux) 491081bdb75Sderaadt { 492081bdb75Sderaadt struct audio_attach_args *sa = aux; 493066545b4Sratchov 494081bdb75Sderaadt return (sa != NULL && (sa->type == AUDIODEV_TYPE_MIDI) ? 1 : 0); 495081bdb75Sderaadt } 496081bdb75Sderaadt 497081bdb75Sderaadt void 498081bdb75Sderaadt midiattach(struct device *parent, struct device *self, void *aux) 499081bdb75Sderaadt { 50079f4179eSratchov struct midi_info mi; 501081bdb75Sderaadt struct midi_softc *sc = (struct midi_softc *)self; 502081bdb75Sderaadt struct audio_attach_args *sa = (struct audio_attach_args *)aux; 5030d6a2fdeSmiod const struct midi_hw_if *hwif = sa->hwif; 504081bdb75Sderaadt void *hdl = sa->hdl; 505081bdb75Sderaadt 506081bdb75Sderaadt #ifdef DIAGNOSTIC 507081bdb75Sderaadt if (hwif == 0 || 508081bdb75Sderaadt hwif->open == 0 || 509081bdb75Sderaadt hwif->close == 0 || 510081bdb75Sderaadt hwif->output == 0 || 511081bdb75Sderaadt hwif->getinfo == 0) { 51202e0ccc4Sratchov printf("%s: missing method\n", DEVNAME(sc)); 513081bdb75Sderaadt return; 514081bdb75Sderaadt } 515081bdb75Sderaadt #endif 51602e0ccc4Sratchov 517cedac2f9Smvs klist_init_mutex(&sc->inbuf.klist, &audio_lock); 518cedac2f9Smvs klist_init_mutex(&sc->outbuf.klist, &audio_lock); 51902e0ccc4Sratchov 520081bdb75Sderaadt sc->hw_if = hwif; 521081bdb75Sderaadt sc->hw_hdl = hdl; 52279f4179eSratchov sc->hw_if->getinfo(sc->hw_hdl, &mi); 52379f4179eSratchov sc->props = mi.props; 524c8d03e3aSratchov sc->flags = 0; 52579f4179eSratchov timeout_set(&sc->timeo, midi_timeout, sc); 52679f4179eSratchov printf(": <%s>\n", mi.name); 527081bdb75Sderaadt } 528081bdb75Sderaadt 529081bdb75Sderaadt int 530081bdb75Sderaadt mididetach(struct device *self, int flags) 531081bdb75Sderaadt { 532081bdb75Sderaadt struct midi_softc *sc = (struct midi_softc *)self; 533081bdb75Sderaadt int maj, mn; 534081bdb75Sderaadt 535081bdb75Sderaadt /* locate the major number */ 536d3538cb0Sratchov for (maj = 0; maj < nchrdev; maj++) { 537d3538cb0Sratchov if (cdevsw[maj].d_open == midiopen) { 538081bdb75Sderaadt /* Nuke the vnodes for any open instances (calls close). */ 539081bdb75Sderaadt mn = self->dv_unit; 540081bdb75Sderaadt vdevgone(maj, mn, mn, VCHR); 541d3538cb0Sratchov } 542d3538cb0Sratchov } 543d0b9e3b5Sratchov 544d0b9e3b5Sratchov /* 545d0b9e3b5Sratchov * The close() method did nothing (device_lookup() returns 546d0b9e3b5Sratchov * NULL), so quickly halt transfers (normally parent is already 547d0b9e3b5Sratchov * gone, and code below is no-op), and wake-up user-land blocked 548d0b9e3b5Sratchov * in read/write/ioctl, which return EIO. 549d0b9e3b5Sratchov */ 550d0b9e3b5Sratchov if (sc->flags) { 551501ade62Sratchov KERNEL_ASSERT_LOCKED(); 552cedac2f9Smvs if (sc->flags & FREAD) 553501ade62Sratchov wakeup(&sc->inbuf.blocking); 554cedac2f9Smvs if (sc->flags & FWRITE) 555501ade62Sratchov wakeup(&sc->outbuf.blocking); 556d0b9e3b5Sratchov sc->hw_if->close(sc->hw_hdl); 557d0b9e3b5Sratchov sc->flags = 0; 558d0b9e3b5Sratchov } 559501ade62Sratchov 560cedac2f9Smvs klist_invalidate(&sc->inbuf.klist); 561cedac2f9Smvs klist_invalidate(&sc->outbuf.klist); 562cedac2f9Smvs klist_free(&sc->inbuf.klist); 563cedac2f9Smvs klist_free(&sc->outbuf.klist); 564501ade62Sratchov 565081bdb75Sderaadt return 0; 566081bdb75Sderaadt } 567081bdb75Sderaadt 568081bdb75Sderaadt int 569081bdb75Sderaadt midiprint(void *aux, const char *pnp) 5702e92e48dSfgsch { 5712e92e48dSfgsch if (pnp) 5722e92e48dSfgsch printf("midi at %s", pnp); 5732e92e48dSfgsch return (UNCONF); 5745daee67fSniklas } 5755daee67fSniklas 576081bdb75Sderaadt struct device * 5770d6a2fdeSmiod midi_attach_mi(const struct midi_hw_if *hwif, void *hdl, struct device *dev) 578081bdb75Sderaadt { 579081bdb75Sderaadt struct audio_attach_args arg; 580081bdb75Sderaadt 581081bdb75Sderaadt arg.type = AUDIODEV_TYPE_MIDI; 582081bdb75Sderaadt arg.hwif = hwif; 583081bdb75Sderaadt arg.hdl = hdl; 584081bdb75Sderaadt return config_found(dev, &arg, midiprint); 585081bdb75Sderaadt } 586