The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/midi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: midi.c,v 1.37 2003/12/04 13:57:30 keihan Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (augustss@NetBSD.org).
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __KERNEL_RCSID(0, "$NetBSD: midi.c,v 1.37 2003/12/04 13:57:30 keihan Exp $");
   41 
   42 #include "midi.h"
   43 #include "sequencer.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/ioctl.h>
   47 #include <sys/fcntl.h>
   48 #include <sys/vnode.h>
   49 #include <sys/select.h>
   50 #include <sys/poll.h>
   51 #include <sys/malloc.h>
   52 #include <sys/proc.h>
   53 #include <sys/systm.h>
   54 #include <sys/callout.h>
   55 #include <sys/syslog.h>
   56 #include <sys/kernel.h>
   57 #include <sys/signalvar.h>
   58 #include <sys/conf.h>
   59 #include <sys/audioio.h>
   60 #include <sys/midiio.h>
   61 #include <sys/device.h>
   62 
   63 #include <dev/audio_if.h>
   64 #include <dev/midi_if.h>
   65 #include <dev/midivar.h>
   66 
   67 #if NMIDI > 0
   68 
   69 #ifdef AUDIO_DEBUG
   70 #define DPRINTF(x)      if (mididebug) printf x
   71 #define DPRINTFN(n,x)   if (mididebug >= (n)) printf x
   72 int     mididebug = 0;
   73 #else
   74 #define DPRINTF(x)
   75 #define DPRINTFN(n,x)
   76 #endif
   77 
   78 int midi_wait;
   79 
   80 void    midi_in(void *, int);
   81 void    midi_out(void *);
   82 int     midi_start_output(struct midi_softc *, int);
   83 int     midi_sleep_timo(int *, char *, int);
   84 int     midi_sleep(int *, char *);
   85 void    midi_wakeup(int *);
   86 void    midi_initbuf(struct midi_buffer *);
   87 void    midi_timeout(void *);
   88 
   89 int     midiprobe(struct device *, struct cfdata *, void *);
   90 void    midiattach(struct device *, struct device *, void *);
   91 int     mididetach(struct device *, int);
   92 int     midiactivate(struct device *, enum devact);
   93 
   94 dev_type_open(midiopen);
   95 dev_type_close(midiclose);
   96 dev_type_read(midiread);
   97 dev_type_write(midiwrite);
   98 dev_type_ioctl(midiioctl);
   99 dev_type_poll(midipoll);
  100 dev_type_kqfilter(midikqfilter);
  101 
  102 const struct cdevsw midi_cdevsw = {
  103         midiopen, midiclose, midiread, midiwrite, midiioctl,
  104         nostop, notty, midipoll, nommap, midikqfilter,
  105 };
  106 
  107 CFATTACH_DECL(midi, sizeof(struct midi_softc),
  108     midiprobe, midiattach, mididetach, midiactivate);
  109 
  110 #ifdef MIDI_SAVE
  111 #define MIDI_SAVE_SIZE 100000
  112 int midicnt;
  113 struct {
  114         int cnt;
  115         u_char buf[MIDI_SAVE_SIZE];
  116 } midisave;
  117 #define MIDI_GETSAVE            _IOWR('m', 100, int)
  118 
  119 #endif
  120 
  121 extern struct cfdriver midi_cd;
  122 
  123 int
  124 midiprobe(struct device *parent, struct cfdata *match, void *aux)
  125 {
  126         struct audio_attach_args *sa = aux;
  127 
  128         DPRINTFN(6,("midiprobe: type=%d sa=%p hw=%p\n", 
  129                  sa->type, sa, sa->hwif));
  130         return (sa->type == AUDIODEV_TYPE_MIDI);
  131 }
  132 
  133 void
  134 midiattach(struct device *parent, struct device *self, void *aux)
  135 {
  136         struct midi_softc *sc = (void *)self;
  137         struct audio_attach_args *sa = aux;
  138         struct midi_hw_if *hwp = sa->hwif;
  139         void *hdlp = sa->hdl;
  140 
  141         DPRINTFN(6, ("MIDI attach\n"));
  142 
  143 #ifdef DIAGNOSTIC
  144         if (hwp == 0 ||
  145             hwp->open == 0 ||
  146             hwp->close == 0 ||
  147             hwp->output == 0 ||
  148             hwp->getinfo == 0) {
  149                 printf("midi: missing method\n");
  150                 return;
  151         }
  152 #endif
  153 
  154         callout_init(&sc->sc_callout);
  155 
  156         sc->hw_if = hwp;
  157         sc->hw_hdl = hdlp;
  158         sc->dying = 0;
  159         midi_attach(sc, parent);
  160 }
  161 
  162 int
  163 midiactivate(struct device *self, enum devact act)
  164 {
  165         struct midi_softc *sc = (struct midi_softc *)self;
  166 
  167         switch (act) {
  168         case DVACT_ACTIVATE:
  169                 return (EOPNOTSUPP);
  170 
  171         case DVACT_DEACTIVATE:
  172                 sc->dying = 1;
  173                 break;
  174         }
  175         return (0);
  176 }
  177 
  178 int
  179 mididetach(struct device *self, int flags)
  180 {
  181         struct midi_softc *sc = (struct midi_softc *)self;
  182         int maj, mn;
  183 
  184         DPRINTF(("midi_detach: sc=%p flags=%d\n", sc, flags));
  185 
  186         sc->dying = 1;
  187 
  188         wakeup(&sc->wchan);
  189         wakeup(&sc->rchan);
  190 
  191         /* locate the major number */
  192         maj = cdevsw_lookup_major(&midi_cdevsw);
  193 
  194         /* Nuke the vnodes for any open instances (calls close). */
  195         mn = self->dv_unit;
  196         vdevgone(maj, mn, mn, VCHR);
  197 
  198         return (0);
  199 }
  200 
  201 void
  202 midi_attach(struct midi_softc *sc, struct device *parent)
  203 {
  204         struct midi_info mi;
  205 
  206         sc->isopen = 0;
  207 
  208         midi_wait = MIDI_WAIT * hz / 1000000;
  209         if (midi_wait == 0)
  210                 midi_wait = 1;
  211 
  212         sc->sc_dev = parent;
  213         sc->hw_if->getinfo(sc->hw_hdl, &mi);
  214         sc->props = mi.props;
  215         printf(": %s\n", mi.name);
  216 }
  217 
  218 int
  219 midi_unit_count(void)
  220 {
  221         return midi_cd.cd_ndevs;
  222 }
  223 
  224 void
  225 midi_initbuf(struct midi_buffer *mb)
  226 {
  227         mb->used = 0;
  228         mb->usedhigh = MIDI_BUFSIZE;
  229         mb->end = mb->start + mb->usedhigh;
  230         mb->inp = mb->outp = mb->start;
  231 }
  232 
  233 int
  234 midi_sleep_timo(int *chan, char *label, int timo)
  235 {
  236         int st;
  237 
  238         if (!label)
  239                 label = "midi";
  240 
  241         DPRINTFN(5, ("midi_sleep_timo: %p %s %d\n", chan, label, timo));
  242         *chan = 1;
  243         st = tsleep(chan, PWAIT | PCATCH, label, timo);
  244         *chan = 0;
  245 #ifdef MIDI_DEBUG
  246         if (st != 0)
  247                 printf("midi_sleep: %d\n", st);
  248 #endif
  249         return st;
  250 }
  251 
  252 int
  253 midi_sleep(int *chan, char *label)
  254 {
  255         return midi_sleep_timo(chan, label, 0);
  256 }
  257 
  258 void
  259 midi_wakeup(int *chan)
  260 {
  261         if (*chan) {
  262                 DPRINTFN(5, ("midi_wakeup: %p\n", chan));
  263                 wakeup(chan);
  264                 *chan = 0;
  265         }
  266 }
  267 
  268 static int midi_lengths[] = { 2,2,2,2,1,1,2,0 };
  269 /* Number of bytes in a MIDI command */
  270 #define MIDI_LENGTH(d) (midi_lengths[((d) >> 4) & 7])
  271 
  272 void
  273 midi_in(void *addr, int data)
  274 {
  275         struct midi_softc *sc = addr;
  276         struct midi_buffer *mb = &sc->inbuf;
  277         int i;
  278 
  279         if (!sc->isopen)
  280                 return;
  281         if (data == MIDI_ACK)
  282                 return;
  283 
  284         DPRINTFN(3, ("midi_in: sc=%p data=0x%02x state=%d pos=%d\n", 
  285                      sc, data, sc->in_state, sc->in_pos));
  286 
  287         if (!(sc->flags & FREAD))
  288                 return;         /* discard data if not reading */
  289 
  290         switch(sc->in_state) {
  291         case MIDI_IN_START:
  292                 if (MIDI_IS_STATUS(data)) {
  293                         switch(data) {
  294                         case 0xf0: /* Sysex */
  295                                 sc->in_state = MIDI_IN_SYSEX;
  296                                 sc->in_msg[0] = data;
  297                                 sc->in_pos = 1;
  298                                 sc->in_left = 0;
  299                                 goto deliver_raw;
  300                         case 0xf1: /* MTC quarter frame */
  301                         case 0xf3: /* Song select */
  302                                 sc->in_state = MIDI_IN_DATA;
  303                                 sc->in_msg[0] = data;
  304                                 sc->in_pos = 1;
  305                                 sc->in_left = 1;
  306                                 break;
  307                         case 0xf2: /* Song position pointer */
  308                                 sc->in_state = MIDI_IN_DATA;
  309                                 sc->in_msg[0] = data;
  310                                 sc->in_pos = 1;
  311                                 sc->in_left = 2;
  312                                 break;
  313                         default:
  314                                 if (MIDI_IS_COMMON(data)) {
  315                                         sc->in_msg[0] = data;
  316                                         sc->in_pos = 1;
  317                                         goto deliver;
  318                                 } else {
  319                                         sc->in_state = MIDI_IN_DATA;
  320                                         sc->in_msg[0] = sc->in_status = data;
  321                                         sc->in_pos = 1;
  322                                         sc->in_left = MIDI_LENGTH(data);
  323                                 }
  324                                 break;
  325                         }
  326                 } else {
  327                         if (MIDI_IS_STATUS(sc->in_status)) {
  328                                 sc->in_state = MIDI_IN_DATA;
  329                                 sc->in_msg[0] = sc->in_status;
  330                                 sc->in_msg[1] = data;
  331                                 sc->in_pos = 2;
  332                                 sc->in_left = MIDI_LENGTH(sc->in_status) - 1;
  333                                 if (sc->in_left == 0)
  334                                     goto deliver;
  335                         }
  336                 }
  337                 return;
  338         case MIDI_IN_DATA:
  339                 KASSERT(sc->in_left >= 1);
  340                 KASSERT(sc->in_pos < 3);
  341                 sc->in_msg[sc->in_pos++] = data;
  342                 if (--sc->in_left == 0)
  343                         break;  /* deliver data */
  344                 return;
  345         case MIDI_IN_SYSEX:
  346                 sc->in_msg[0] = data;
  347                 sc->in_pos = 1;
  348                 sc->in_left = 0;
  349                 if (data == MIDI_SYSEX_END)
  350                         sc->in_state = MIDI_IN_START;
  351                 goto deliver_raw;
  352         }
  353 deliver:
  354         sc->in_state = MIDI_IN_START;
  355 #if NSEQUENCER > 0
  356         if (sc->seqopen) {
  357                 extern void midiseq_in(struct midi_dev *,u_char *,int);
  358                 midiseq_in(sc->seq_md, sc->in_msg, sc->in_pos);
  359                 return;
  360         }
  361 #endif
  362  deliver_raw:
  363         if (mb->used + sc->in_pos > mb->usedhigh) {
  364                 DPRINTF(("midi_in: buffer full, discard data=0x%02x\n", 
  365                          sc->in_msg[0]));
  366                 return;
  367         }
  368         for (i = 0; i < sc->in_pos; i++) {
  369                 *mb->inp++ = sc->in_msg[i];
  370                 if (mb->inp >= mb->end)
  371                         mb->inp = mb->start;
  372                 mb->used++;
  373         }
  374         midi_wakeup(&sc->rchan);
  375         selnotify(&sc->rsel, 0);
  376         if (sc->async)
  377                 psignal(sc->async, SIGIO);
  378 }
  379 
  380 void
  381 midi_out(void *addr)
  382 {
  383         struct midi_softc *sc = addr;
  384 
  385         if (!sc->isopen)
  386                 return;
  387         DPRINTFN(3, ("midi_out: %p\n", sc));
  388         midi_start_output(sc, 1);
  389 }
  390 
  391 int
  392 midiopen(dev_t dev, int flags, int ifmt, struct proc *p)
  393 {
  394         struct midi_softc *sc;
  395         struct midi_hw_if *hw;
  396         int error;
  397 
  398         sc = device_lookup(&midi_cd, MIDIUNIT(dev));
  399         if (sc == NULL)
  400                 return (ENXIO);
  401         if (sc->dying)
  402                 return (EIO);
  403 
  404         DPRINTF(("midiopen %p\n", sc));
  405 
  406         hw = sc->hw_if;
  407         if (!hw)
  408                 return ENXIO;
  409         if (sc->isopen)
  410                 return EBUSY;
  411         sc->in_state = MIDI_IN_START;
  412         sc->in_status = 0;
  413         error = hw->open(sc->hw_hdl, flags, midi_in, midi_out, sc);
  414         if (error)
  415                 return error;
  416         sc->isopen++;
  417         midi_initbuf(&sc->outbuf);
  418         midi_initbuf(&sc->inbuf);
  419         sc->flags = flags;
  420         sc->rchan = 0;
  421         sc->wchan = 0;
  422         sc->pbus = 0;
  423         sc->async = 0;
  424 
  425 #ifdef MIDI_SAVE
  426         if (midicnt != 0) {
  427                 midisave.cnt = midicnt;
  428                 midicnt = 0;
  429         }
  430 #endif
  431 
  432         return 0;
  433 }
  434 
  435 int
  436 midiclose(dev_t dev, int flags, int ifmt, struct proc *p)
  437 {
  438         int unit = MIDIUNIT(dev);
  439         struct midi_softc *sc = midi_cd.cd_devs[unit];
  440         struct midi_hw_if *hw = sc->hw_if;
  441         int s, error;
  442 
  443         DPRINTF(("midiclose %p\n", sc));
  444 
  445         midi_start_output(sc, 0);
  446         error = 0;
  447         s = splaudio();
  448         while (sc->outbuf.used > 0 && !error) {
  449                 DPRINTFN(2,("midiclose sleep used=%d\n", sc->outbuf.used));
  450                 error = midi_sleep_timo(&sc->wchan, "mid_dr", 30*hz);
  451         }
  452         splx(s);
  453         sc->isopen = 0;
  454         hw->close(sc->hw_hdl);
  455 #if NSEQUENCER > 0
  456         sc->seqopen = 0;
  457         sc->seq_md = 0;
  458 #endif
  459         return 0;
  460 }
  461 
  462 int
  463 midiread(dev_t dev, struct uio *uio, int ioflag)
  464 {
  465         int unit = MIDIUNIT(dev);
  466         struct midi_softc *sc = midi_cd.cd_devs[unit];
  467         struct midi_buffer *mb = &sc->inbuf;
  468         int error;
  469         u_char *outp;
  470         int used, cc, n, resid;
  471         int s;
  472 
  473         DPRINTF(("midiread: %p, count=%lu\n", sc, 
  474                  (unsigned long)uio->uio_resid));
  475 
  476         if (sc->dying)
  477                 return EIO;
  478 
  479         error = 0;
  480         resid = uio->uio_resid;
  481         while (uio->uio_resid == resid && !error) {
  482                 s = splaudio();
  483                 while (mb->used <= 0) {
  484                         if (ioflag & IO_NDELAY) {
  485                                 splx(s);
  486                                 return EWOULDBLOCK;
  487                         }
  488                         error = midi_sleep(&sc->rchan, "mid rd");
  489                         if (error) {
  490                                 splx(s);
  491                                 return error;
  492                         }
  493                 }
  494                 used = mb->used;
  495                 outp = mb->outp;
  496                 splx(s);
  497                 if (sc->dying)
  498                         return EIO;
  499                 cc = used;      /* maximum to read */
  500                 n = mb->end - outp;
  501                 if (n < cc)
  502                         cc = n; /* don't read beyond end of buffer */
  503                 if (uio->uio_resid < cc)
  504                         cc = uio->uio_resid; /* and no more than we want */
  505                 DPRINTFN(3, ("midiread: uiomove cc=%d\n", cc));
  506                 error = uiomove(outp, cc, uio);
  507                 if (error)
  508                         break;
  509                 used -= cc;
  510                 outp += cc;
  511                 if (outp >= mb->end)
  512                         outp = mb->start;
  513                 s = splaudio();
  514                 mb->outp = outp;
  515                 mb->used = used;
  516                 splx(s);
  517         }
  518         return error;
  519 }
  520 
  521 void
  522 midi_timeout(void *arg)
  523 {
  524         struct midi_softc *sc = arg;
  525 
  526         DPRINTFN(3,("midi_timeout: %p\n", sc));
  527         midi_start_output(sc, 1);
  528 }
  529 
  530 int
  531 midi_start_output(struct midi_softc *sc, int intr)
  532 {
  533         struct midi_buffer *mb = &sc->outbuf;
  534         u_char out;
  535         int error;
  536         int s;
  537         int i;
  538 
  539         error = 0;
  540 
  541         if (sc->dying)
  542                 return EIO;
  543 
  544         if (sc->pbus && !intr) {
  545                 DPRINTFN(4, ("midi_start_output: busy\n"));
  546                 return 0;
  547         }
  548         sc->pbus = (mb->used > 0)?1:0;
  549         for (i = 0; i < MIDI_MAX_WRITE && mb->used > 0 &&
  550                    (!error || error==EINPROGRESS); i++) {
  551                 s = splaudio();
  552                 out = *mb->outp;
  553                 mb->outp++;
  554                 if (mb->outp >= mb->end)
  555                         mb->outp = mb->start;
  556                 mb->used--;
  557                 splx(s);
  558 #ifdef MIDI_SAVE
  559                 midisave.buf[midicnt] = out;
  560                 midicnt = (midicnt + 1) % MIDI_SAVE_SIZE;
  561 #endif
  562                 DPRINTFN(4, ("midi_start_output: %p i=%d, data=0x%02x\n", 
  563                              sc, i, out));
  564                 error = sc->hw_if->output(sc->hw_hdl, out);
  565                 if ((sc->props & MIDI_PROP_OUT_INTR) && error!=EINPROGRESS)
  566                         /* If ointr is enabled, midi_start_output()
  567                          * normally writes only one byte,
  568                          * except hw_if->output() returns EINPROGRESS.
  569                          */
  570                         break;
  571         }
  572         midi_wakeup(&sc->wchan);
  573         selnotify(&sc->wsel, 0);
  574         if (sc->async)
  575                 psignal(sc->async, SIGIO);
  576         if (!(sc->props & MIDI_PROP_OUT_INTR) || error==EINPROGRESS) {
  577                 if (mb->used > 0)
  578                         callout_reset(&sc->sc_callout, midi_wait,
  579                                       midi_timeout, sc);
  580                 else
  581                         sc->pbus = 0;
  582         }
  583         if ((sc->props & MIDI_PROP_OUT_INTR) && error==EINPROGRESS)
  584                 error = 0;
  585 
  586         return error;
  587 }
  588 
  589 int
  590 midiwrite(dev_t dev, struct uio *uio, int ioflag)
  591 {
  592         int unit = MIDIUNIT(dev);
  593         struct midi_softc *sc = midi_cd.cd_devs[unit];
  594         struct midi_buffer *mb = &sc->outbuf;
  595         int error;
  596         u_char *inp;
  597         int used, cc, n;
  598         int s;
  599 
  600         DPRINTFN(2, ("midiwrite: %p, unit=%d, count=%lu\n", sc, unit, 
  601                      (unsigned long)uio->uio_resid));
  602 
  603         if (sc->dying)
  604                 return EIO;
  605 
  606         error = 0;
  607         while (uio->uio_resid > 0 && !error) {
  608                 s = splaudio();
  609                 if (mb->used >= mb->usedhigh) {
  610                         DPRINTFN(3,("midi_write: sleep used=%d hiwat=%d\n", 
  611                                  mb->used, mb->usedhigh));
  612                         if (ioflag & IO_NDELAY) {
  613                                 splx(s);
  614                                 return EWOULDBLOCK;
  615                         }
  616                         error = midi_sleep(&sc->wchan, "mid wr");
  617                         if (error) {
  618                                 splx(s);
  619                                 return error;
  620                         }
  621                 }                       
  622                 used = mb->used;
  623                 inp = mb->inp;
  624                 splx(s);
  625                 if (sc->dying)
  626                         return EIO;
  627                 cc = mb->usedhigh - used;       /* maximum to write */
  628                 n = mb->end - inp;
  629                 if (n < cc)
  630                         cc = n;         /* don't write beyond end of buffer */
  631                 if (uio->uio_resid < cc)
  632                         cc = uio->uio_resid;    /* and no more than we have */
  633                 error = uiomove(inp, cc, uio);
  634 #ifdef MIDI_DEBUG
  635                 if (error)
  636                         printf("midi_write:(1) uiomove failed %d; "
  637                                "cc=%d inp=%p\n",
  638                                error, cc, inp);
  639 #endif
  640                 if (error)
  641                         break;
  642                 inp = mb->inp + cc;
  643                 if (inp >= mb->end)
  644                         inp = mb->start;
  645                 s = splaudio();
  646                 mb->inp = inp;
  647                 mb->used += cc;
  648                 splx(s);
  649                 error = midi_start_output(sc, 0);
  650         }
  651         return error;
  652 }
  653 
  654 /*
  655  * This write routine is only called from sequencer code and expects
  656  * a write that is smaller than the MIDI buffer.
  657  */
  658 int
  659 midi_writebytes(int unit, u_char *buf, int cc)
  660 {
  661         struct midi_softc *sc = midi_cd.cd_devs[unit];
  662         struct midi_buffer *mb = &sc->outbuf;
  663         int n, s;
  664 
  665         DPRINTFN(2, ("midi_writebytes: %p, unit=%d, cc=%d\n", sc, unit, cc));
  666         DPRINTFN(3, ("midi_writebytes: %x %x %x\n",buf[0],buf[1],buf[2]));
  667 
  668         if (sc->dying)
  669                 return EIO;
  670 
  671         s = splaudio();
  672         if (mb->used + cc >= mb->usedhigh) {
  673                 splx(s);
  674                 return (EWOULDBLOCK);
  675         }
  676         n = mb->end - mb->inp;
  677         if (cc < n)
  678                 n = cc;
  679         mb->used += cc;
  680         memcpy(mb->inp, buf, n);
  681         mb->inp += n;
  682         if (mb->inp >= mb->end) {
  683                 mb->inp = mb->start;
  684                 cc -= n;
  685                 if (cc > 0) {
  686                         memcpy(mb->inp, buf + n, cc);
  687                         mb->inp += cc;
  688                 }
  689         }
  690         splx(s);
  691         return (midi_start_output(sc, 0));
  692 }
  693 
  694 int
  695 midiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  696 {
  697         int unit = MIDIUNIT(dev);
  698         struct midi_softc *sc = midi_cd.cd_devs[unit];
  699         struct midi_hw_if *hw = sc->hw_if;
  700         int error;
  701 
  702         DPRINTF(("midiioctl: %p cmd=0x%08lx\n", sc, cmd));
  703 
  704         if (sc->dying)
  705                 return EIO;
  706 
  707         error = 0;
  708         switch (cmd) {
  709         case FIONBIO:
  710                 /* All handled in the upper FS layer. */
  711                 break;
  712 
  713         case FIOASYNC:
  714                 if (*(int *)addr) {
  715                         if (sc->async)
  716                                 return EBUSY;
  717                         sc->async = p;
  718                         DPRINTF(("midi_ioctl: FIOASYNC %p\n", p));
  719                 } else
  720                         sc->async = 0;
  721                 break;
  722 
  723 #if 0
  724         case MIDI_PRETIME:
  725                 /* XXX OSS
  726                  * This should set up a read timeout, but that's
  727                  * why we have poll(), so there's nothing yet. */
  728                 error = EINVAL;
  729                 break;
  730 #endif
  731 
  732 #ifdef MIDI_SAVE
  733         case MIDI_GETSAVE:
  734                 error = copyout(&midisave, *(void **)addr, sizeof midisave);
  735                 break;
  736 #endif
  737 
  738         default:
  739                 if (hw->ioctl)
  740                         error = hw->ioctl(sc->hw_hdl, cmd, addr, flag, p);
  741                 else
  742                         error = EINVAL;
  743                 break;
  744         }
  745         return error;
  746 }
  747 
  748 int
  749 midipoll(dev_t dev, int events, struct proc *p)
  750 {
  751         int unit = MIDIUNIT(dev);
  752         struct midi_softc *sc = midi_cd.cd_devs[unit];
  753         int revents = 0;
  754         int s;
  755 
  756         DPRINTF(("midipoll: %p events=0x%x\n", sc, events));
  757 
  758         if (sc->dying)
  759                 return EIO;
  760 
  761         s = splaudio();
  762 
  763         if (events & (POLLIN | POLLRDNORM))
  764                 if (sc->inbuf.used > 0)
  765                         revents |= events & (POLLIN | POLLRDNORM);
  766 
  767         if (events & (POLLOUT | POLLWRNORM))
  768                 if (sc->outbuf.used < sc->outbuf.usedhigh)
  769                         revents |= events & (POLLOUT | POLLWRNORM);
  770 
  771         if (revents == 0) {
  772                 if (events & (POLLIN | POLLRDNORM))
  773                         selrecord(p, &sc->rsel);
  774 
  775                 if (events & (POLLOUT | POLLWRNORM))
  776                         selrecord(p, &sc->wsel);
  777         }
  778 
  779         splx(s);
  780         return revents;
  781 }
  782 
  783 static void
  784 filt_midirdetach(struct knote *kn)
  785 {
  786         struct midi_softc *sc = kn->kn_hook;
  787         int s;
  788 
  789         s = splaudio();
  790         SLIST_REMOVE(&sc->rsel.sel_klist, kn, knote, kn_selnext);
  791         splx(s);
  792 }
  793 
  794 static int
  795 filt_midiread(struct knote *kn, long hint)
  796 {
  797         struct midi_softc *sc = kn->kn_hook;
  798 
  799         /* XXXLUKEM (thorpej): please make sure this is correct. */
  800 
  801         kn->kn_data = sc->inbuf.used;
  802         return (kn->kn_data > 0);
  803 }
  804 
  805 static const struct filterops midiread_filtops =
  806         { 1, NULL, filt_midirdetach, filt_midiread };
  807 
  808 static void
  809 filt_midiwdetach(struct knote *kn)
  810 {
  811         struct midi_softc *sc = kn->kn_hook;
  812         int s;
  813 
  814         s = splaudio();
  815         SLIST_REMOVE(&sc->wsel.sel_klist, kn, knote, kn_selnext);
  816         splx(s);
  817 }
  818 
  819 static int
  820 filt_midiwrite(struct knote *kn, long hint)
  821 {
  822         struct midi_softc *sc = kn->kn_hook;
  823 
  824         /* XXXLUKEM (thorpej): please make sure this is correct. */
  825 
  826         kn->kn_data = sc->outbuf.usedhigh - sc->outbuf.used;
  827         return (kn->kn_data > 0);
  828 }
  829 
  830 static const struct filterops midiwrite_filtops =
  831         { 1, NULL, filt_midiwdetach, filt_midiwrite };
  832 
  833 int
  834 midikqfilter(dev_t dev, struct knote *kn)
  835 {
  836         int unit = MIDIUNIT(dev);
  837         struct midi_softc *sc = midi_cd.cd_devs[unit];
  838         struct klist *klist;
  839         int s;
  840 
  841         switch (kn->kn_filter) {
  842         case EVFILT_READ:
  843                 klist = &sc->rsel.sel_klist;
  844                 kn->kn_fop = &midiread_filtops;
  845                 break;
  846 
  847         case EVFILT_WRITE:
  848                 klist = &sc->wsel.sel_klist;
  849                 kn->kn_fop = &midiwrite_filtops;
  850                 break;
  851 
  852         default:
  853                 return (1);
  854         }
  855 
  856         kn->kn_hook = sc;
  857 
  858         s = splaudio();
  859         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  860         splx(s);
  861 
  862         return (0);
  863 }
  864 
  865 void
  866 midi_getinfo(dev_t dev, struct midi_info *mi)
  867 {
  868         struct midi_softc *sc;
  869 
  870         sc = device_lookup(&midi_cd, MIDIUNIT(dev));
  871         if (sc == NULL)
  872                 return;
  873         if (sc->dying)
  874                 return;
  875 
  876         sc->hw_if->getinfo(sc->hw_hdl, mi);
  877 }
  878 
  879 #endif /* NMIDI > 0 */
  880 
  881 #if NMIDI > 0 || NMIDIBUS > 0
  882 
  883 int     audioprint(void *, const char *);
  884 
  885 struct device *
  886 midi_attach_mi(struct midi_hw_if *mhwp, void *hdlp, struct device *dev)
  887 {
  888         struct audio_attach_args arg;
  889 
  890 #ifdef DIAGNOSTIC
  891         if (mhwp == NULL) {
  892                 aprint_error("midi_attach_mi: NULL\n");
  893                 return (0);
  894         }
  895 #endif
  896         arg.type = AUDIODEV_TYPE_MIDI;
  897         arg.hwif = mhwp;
  898         arg.hdl = hdlp;
  899         return (config_found(dev, &arg, audioprint));
  900 }
  901 
  902 #endif /* NMIDI > 0 || NMIDIBUS > 0 */

Cache object: 42d11d5ad0465dcc24c6f4d80e1b9a9b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.