LCOV - code coverage report
Current view: top level - dev - midi.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 290 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13