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/sound/midi/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 /*
    2  * Main midi driver for FreeBSD. This file provides the main
    3  * entry points for probe/attach and all i/o demultiplexing, including
    4  * default routines for generic devices.
    5  * 
    6  * (C) 1999 Seigo Tanimura
    7  * 
    8  * Redistribution and use in source and binary forms, with or
    9  * without modification, are permitted provided that the following
   10  * conditions are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above
   14  *    copyright notice, this list of conditions and the following
   15  *    disclaimer in the documentation and/or other materials provided
   16  *    with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
   19  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   22  * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  *
   32  * For each card type a template "mididev_info" structure contains
   33  * all the relevant parameters, both for configuration and runtime.
   34  *
   35  * In this file we build tables of pointers to the descriptors for
   36  * the various supported cards. The generic probe routine scans
   37  * the table(s) looking for a matching entry, then invokes the
   38  * board-specific probe routine. If successful, a pointer to the
   39  * correct mididev_info is stored in mididev_last_probed, for subsequent
   40  * use in the attach routine. The generic attach routine copies
   41  * the template to a permanent descriptor (midi_info and
   42  * friends), initializes all generic parameters, and calls the
   43  * board-specific attach routine.
   44  *
   45  * On device calls, the generic routines do the checks on unit and
   46  * device parameters, then call the board-specific routines if
   47  * available, or try to perform the task using the default code.
   48  *
   49  * $FreeBSD: releng/5.0/sys/dev/sound/midi/midi.c 93818 2002-04-04 21:03:38Z jhb $
   50  *
   51  */
   52 
   53 #include <dev/sound/midi/midi.h>
   54 
   55 static devclass_t midi_devclass;
   56 
   57 static d_open_t midiopen;
   58 static d_close_t midiclose;
   59 static d_ioctl_t midiioctl;
   60 static d_read_t midiread;
   61 static d_write_t midiwrite;
   62 static d_poll_t midipoll;
   63 
   64 /* These functions are local. */
   65 static d_open_t midistat_open;
   66 static d_close_t midistat_close;
   67 static d_read_t midistat_read;
   68 static int midi_initstatus(char *buf, int size);
   69 static int midi_readstatus(char *buf, int *ptr, struct uio *uio);
   70 
   71 #define CDEV_MAJOR MIDI_CDEV_MAJOR
   72 static struct cdevsw midi_cdevsw = {
   73         /* open */      midiopen,
   74         /* close */     midiclose,
   75         /* read */      midiread,
   76         /* write */     midiwrite,
   77         /* ioctl */     midiioctl,
   78         /* poll */      midipoll,
   79         /* mmap */      nommap,
   80         /* strategy */  nostrategy,
   81         /* name */      "midi",
   82         /* maj */       CDEV_MAJOR,
   83         /* dump */      nodump,
   84         /* psize */     nopsize,
   85         /* flags */     0,
   86 };
   87 
   88 /*
   89  * descriptors for active devices. also used as the public softc
   90  * of a device.
   91  */
   92 static TAILQ_HEAD(,_mididev_info)       midi_info;
   93 static int              nmidi, nsynth;
   94 /* Mutex to protect midi_info, nmidi and nsynth. */
   95 static struct mtx       midiinfo_mtx;
   96 static int              midiinfo_mtx_init;
   97 
   98 /* These make the buffer for /dev/midistat */
   99 static int              midistatbusy;
  100 static char             midistatbuf[4096];
  101 static int              midistatptr;
  102 
  103 SYSCTL_NODE(_hw, OID_AUTO, midi, CTLFLAG_RD, 0, "Midi driver");
  104 
  105 int                     midi_debug;
  106 SYSCTL_INT(_hw_midi, OID_AUTO, debug, CTLFLAG_RW, &midi_debug, 0, "");
  107 
  108 midi_cmdtab     cmdtab_midiioctl[] = {
  109         {SNDCTL_MIDI_PRETIME,   "SNDCTL_MIDI_PRETIME"},
  110         {SNDCTL_MIDI_MPUMODE,   "SNDCTL_MIDI_MPUMODE"},
  111         {SNDCTL_MIDI_MPUCMD,    "SNDCTL_MIDI_MPUCMD"},
  112         {SNDCTL_SYNTH_INFO,     "SNDCTL_SYNTH_INFO"},
  113         {SNDCTL_MIDI_INFO,      "SNDCTL_MIDI_INFO"},
  114         {SNDCTL_SYNTH_MEMAVL,   "SNDCTL_SYNTH_MEMAVL"},
  115         {SNDCTL_FM_LOAD_INSTR,  "SNDCTL_FM_LOAD_INSTR"},
  116         {SNDCTL_FM_4OP_ENABLE,  "SNDCTL_FM_4OP_ENABLE"},
  117         {MIOSPASSTHRU,          "MIOSPASSTHRU"},
  118         {MIOGPASSTHRU,          "MIOGPASSTHRU"},
  119         {AIONWRITE,             "AIONWRITE"},
  120         {AIOGSIZE,              "AIOGSIZE"},
  121         {AIOSSIZE,              "AIOSSIZE"},
  122         {AIOGFMT,               "AIOGFMT"},
  123         {AIOSFMT,               "AIOSFMT"},
  124         {AIOGMIX,               "AIOGMIX"},
  125         {AIOSMIX,               "AIOSMIX"},
  126         {AIOSTOP,               "AIOSTOP"},
  127         {AIOSYNC,               "AIOSYNC"},
  128         {AIOGCAP,               "AIOGCAP"},
  129         {-1,                    NULL},
  130 };
  131 
  132 /*
  133  * This is the generic init routine.
  134  * Must be called after device-specific init.
  135  */
  136 int
  137 midiinit(mididev_info *d, device_t dev)
  138 {
  139         int unit;
  140 
  141         /*
  142          * initialize standard parameters for the device. This can be
  143          * overridden by device-specific configurations but better do
  144          * here the generic things.
  145          */
  146 
  147         MIDI_DEBUG(printf("midiinit: unit %d.\n", d->unit));
  148 
  149         unit = d->unit;
  150         d->softc = device_get_softc(dev);
  151         d->dev = dev;
  152         d->magic = MAGIC(d->unit); /* debugging... */
  153         d->flags = 0;
  154         d->fflags = 0;
  155         d->midi_dbuf_in.unit_size = 1;
  156         d->midi_dbuf_out.unit_size = 1;
  157         d->midi_dbuf_passthru.unit_size = 1;
  158 
  159         mtx_unlock(&d->flagqueue_mtx);
  160 
  161         if (midi_devclass == NULL) {
  162                 midi_devclass = device_get_devclass(dev);
  163                 make_dev(&midi_cdevsw, MIDIMKMINOR(0, MIDI_DEV_STATUS),
  164                          UID_ROOT, GID_WHEEL, 0444, "midistat");
  165         }
  166         make_dev(&midi_cdevsw, MIDIMKMINOR(unit, MIDI_DEV_MIDIN),
  167                  UID_ROOT, GID_WHEEL, 0666, "midi%d", unit);
  168 
  169         return 0 ;
  170 }
  171 
  172 /*
  173  * a small utility function which, given a device number, returns
  174  * a pointer to the associated mididev_info struct, and sets the unit
  175  * number.
  176  */
  177 mididev_info *
  178 get_mididev_info(dev_t i_dev, int *unit)
  179 {
  180         int u;
  181 
  182         if (MIDIDEV(i_dev) != MIDI_DEV_MIDIN)
  183                 return NULL;
  184         u = MIDIUNIT(i_dev);
  185         if (unit)
  186                 *unit = u;
  187 
  188         return get_mididev_info_unit(u);
  189 }
  190 
  191 /*
  192  * a small utility function which, given a unit number, returns
  193  * a pointer to the associated mididev_info struct.
  194  */
  195 mididev_info *
  196 get_mididev_info_unit(int unit)
  197 {
  198         mididev_info *md;
  199 
  200         /* XXX */
  201         if (!midiinfo_mtx_init) {
  202                 midiinfo_mtx_init = 1;
  203                 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
  204                 TAILQ_INIT(&midi_info);
  205         }
  206 
  207         mtx_lock(&midiinfo_mtx);
  208         TAILQ_FOREACH(md, &midi_info, md_link) {
  209                 if (md->unit == unit)
  210                         break;
  211         }
  212         mtx_unlock(&midiinfo_mtx);
  213 
  214         return md;
  215 }
  216 
  217 /*
  218  * a small utility function which, given a unit number, returns
  219  * a pointer to the associated mididev_info struct with MDT_MIDI.
  220  */
  221 mididev_info *
  222 get_mididev_midi_unit(int unit)
  223 {
  224         mididev_info *md;
  225 
  226         /* XXX */
  227         if (!midiinfo_mtx_init) {
  228                 midiinfo_mtx_init = 1;
  229                 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
  230                 TAILQ_INIT(&midi_info);
  231         }
  232 
  233         mtx_lock(&midiinfo_mtx);
  234         TAILQ_FOREACH(md, &midi_info, md_link) {
  235                 if (md->midiunit == unit)
  236                         break;
  237         }
  238         mtx_unlock(&midiinfo_mtx);
  239 
  240         return md;
  241 }
  242 
  243 /*
  244  * a small utility function which, given a unit number, returns
  245  * a pointer to the associated mididev_info struct with MDT_SYNTH.
  246  */
  247 mididev_info *
  248 get_mididev_synth_unit(int unit)
  249 {
  250         mididev_info *md;
  251 
  252         /* XXX */
  253         if (!midiinfo_mtx_init) {
  254                 midiinfo_mtx_init = 1;
  255                 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
  256                 TAILQ_INIT(&midi_info);
  257         }
  258 
  259         mtx_lock(&midiinfo_mtx);
  260         TAILQ_FOREACH(md, &midi_info, md_link) {
  261                 if (md->synthunit == unit)
  262                         break;
  263         }
  264         mtx_unlock(&midiinfo_mtx);
  265 
  266         return md;
  267 }
  268 
  269 /* Create a new midi device info structure. */
  270 /* TODO: lock md, then exit. */
  271 mididev_info *
  272 create_mididev_info_unit(int type, mididev_info *mdinf, synthdev_info *syninf)
  273 {
  274         int unit;
  275         mididev_info *md, *mdnew;
  276 
  277         /* XXX */
  278         if (!midiinfo_mtx_init) {
  279                 midiinfo_mtx_init = 1;
  280                 mtx_init(&midiinfo_mtx, "midinf", NULL, MTX_DEF);
  281                 TAILQ_INIT(&midi_info);
  282         }
  283 
  284         /* As malloc(9) might block, allocate mididev_info now. */
  285         mdnew = malloc(sizeof(mididev_info), M_DEVBUF, M_WAITOK | M_ZERO);
  286         if (mdnew == NULL)
  287                 return NULL;
  288         bcopy(mdinf, mdnew, sizeof(mididev_info));
  289         bcopy(syninf, &mdnew->synth, sizeof(synthdev_info));
  290         midibuf_init(&mdnew->midi_dbuf_in);
  291         midibuf_init(&mdnew->midi_dbuf_out);
  292         midibuf_init(&mdnew->midi_dbuf_passthru);
  293         mtx_init(&mdnew->flagqueue_mtx, "midflq", NULL, MTX_DEF);
  294         mtx_init(&mdnew->synth.vc_mtx, "synsvc", NULL, MTX_DEF);
  295         mtx_init(&mdnew->synth.status_mtx, "synsst", NULL, MTX_DEF);
  296 
  297         mtx_lock(&midiinfo_mtx);
  298 
  299         switch (type) {
  300         case MDT_MIDI:
  301                 mdnew->midiunit = nmidi;
  302                 mdnew->synthunit = nmidi;
  303                 nmidi++;
  304                 break;
  305         case MDT_SYNTH:
  306                 mdnew->midiunit = -1;
  307                 mdnew->synthunit = nsynth;
  308                 nsynth++;
  309                 break;
  310         default:
  311                 mtx_unlock(&midiinfo_mtx);
  312                 midibuf_destroy(&mdnew->midi_dbuf_in);
  313                 midibuf_destroy(&mdnew->midi_dbuf_out);
  314                 midibuf_destroy(&mdnew->midi_dbuf_passthru);
  315                 mtx_destroy(&mdnew->flagqueue_mtx);
  316                 mtx_destroy(&mdnew->synth.vc_mtx);
  317                 mtx_destroy(&mdnew->synth.status_mtx);
  318                 free(mdnew, M_DEVBUF);
  319                 panic("unsupported device type");
  320                 return NULL;
  321         }
  322         mdnew->mdtype = type;
  323 
  324         for (unit = 0 ; ; unit++) {
  325                 TAILQ_FOREACH(md, &midi_info, md_link) {
  326                         if (md->unit == unit)
  327                                 break;
  328                 }
  329                 if (md == NULL)
  330                         break;
  331         }
  332 
  333         mdnew->unit = unit;
  334         mtx_lock(&mdnew->flagqueue_mtx);
  335         TAILQ_INSERT_TAIL(&midi_info, mdnew, md_link);
  336 
  337         mtx_unlock(&midiinfo_mtx);
  338 
  339         return mdnew;
  340 }
  341 
  342 /* Return the number of configured devices. */
  343 int
  344 mididev_info_number(void)
  345 {
  346         return nmidi + nsynth;
  347 }
  348 
  349 /* Return the number of configured midi devices. */
  350 int
  351 mididev_midi_number(void)
  352 {
  353         return nmidi;
  354 }
  355 
  356 /* Return the number of configured synth devices. */
  357 int
  358 mididev_synth_number(void)
  359 {
  360         return nsynth;
  361 }
  362 
  363 /*
  364  * here are the switches for the main functions. The switches do
  365  * all necessary checks on the device number to make sure
  366  * that the device is configured. They also provide some default
  367  * functionalities so that device-specific drivers have to deal
  368  * only with special cases.
  369  */
  370 
  371 static int
  372 midiopen(dev_t i_dev, int flags, int mode, struct thread *td)
  373 {
  374         int ret;
  375 
  376         switch (MIDIDEV(i_dev)) {
  377         case MIDI_DEV_MIDIN:
  378                 ret = midi_open(i_dev, flags, mode, td);
  379                 break;
  380         case MIDI_DEV_STATUS:
  381                 ret = midistat_open(i_dev, flags, mode, td);
  382                 break;
  383         default:
  384                 ret = ENXIO;
  385                 break;
  386         }
  387 
  388         return (ret);
  389 }
  390 
  391 static int
  392 midiclose(dev_t i_dev, int flags, int mode, struct thread *td)
  393 {
  394         int ret;
  395 
  396         switch (MIDIDEV(i_dev)) {
  397         case MIDI_DEV_MIDIN:
  398                 ret = midi_close(i_dev, flags, mode, td);
  399                 break;
  400         case MIDI_DEV_STATUS:
  401                 ret = midistat_close(i_dev, flags, mode, td);
  402                 break;
  403         default:
  404                 ret = ENXIO;
  405                 break;
  406         }
  407 
  408         return (ret);
  409 }
  410 
  411 static int
  412 midiread(dev_t i_dev, struct uio * buf, int flag)
  413 {
  414         int ret;
  415 
  416         switch (MIDIDEV(i_dev)) {
  417         case MIDI_DEV_MIDIN:
  418                 ret = midi_read(i_dev, buf, flag);
  419                 break;
  420         case MIDI_DEV_STATUS:
  421                 ret = midistat_read(i_dev, buf, flag);
  422                 break;
  423         default:
  424                 ret = ENXIO;
  425                 break;
  426         }
  427 
  428         return (ret);
  429 }
  430 
  431 static int
  432 midiwrite(dev_t i_dev, struct uio * buf, int flag)
  433 {
  434         int ret;
  435 
  436         switch (MIDIDEV(i_dev)) {
  437         case MIDI_DEV_MIDIN:
  438                 ret = midi_write(i_dev, buf, flag);
  439                 break;
  440         default:
  441                 ret = ENXIO;
  442                 break;
  443         }
  444 
  445         return (ret);
  446 }
  447 
  448 static int
  449 midiioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  450 {
  451         int ret;
  452 
  453         switch (MIDIDEV(i_dev)) {
  454         case MIDI_DEV_MIDIN:
  455                 ret = midi_ioctl(i_dev, cmd, arg, mode, td);
  456                 break;
  457         default:
  458                 ret = ENXIO;
  459                 break;
  460         }
  461 
  462         return (ret);
  463 }
  464 
  465 static int
  466 midipoll(dev_t i_dev, int events, struct thread *td)
  467 {
  468         int ret;
  469 
  470         switch (MIDIDEV(i_dev)) {
  471         case MIDI_DEV_MIDIN:
  472                 ret = midi_poll(i_dev, events, td);
  473                 break;
  474         default:
  475                 ret = ENXIO;
  476                 break;
  477         }
  478 
  479         return (ret);
  480 }
  481 
  482 /*
  483  * Followings are the generic methods in midi drivers.
  484  */
  485 
  486 int
  487 midi_open(dev_t i_dev, int flags, int mode, struct thread *td)
  488 {
  489         int dev, unit, ret;
  490         mididev_info *d;
  491 
  492         dev = minor(i_dev);
  493         d = get_mididev_info(i_dev, &unit);
  494 
  495         MIDI_DEBUG(printf("midi_open: unit %d, flags 0x%x.\n", unit, flags));
  496 
  497         if (d == NULL)
  498                 return (ENXIO);
  499 
  500         /* Mark this device busy. */
  501         mtx_lock(&d->flagqueue_mtx);
  502         device_busy(d->dev);
  503         if ((d->flags & MIDI_F_BUSY) != 0) {
  504                 mtx_unlock(&d->flagqueue_mtx);
  505                 printf("midi_open: unit %d is busy.\n", unit);
  506                 return (EBUSY);
  507         }
  508         d->fflags = flags;
  509         d->flags |= MIDI_F_BUSY;
  510         d->flags &= ~(MIDI_F_READING | MIDI_F_WRITING);
  511         if ((d->fflags & O_NONBLOCK) != 0)
  512                 d->flags |= MIDI_F_NBIO;
  513 
  514         /* Init the queue. */
  515         if ((flags & FREAD) != 0)
  516                 midibuf_clear(&d->midi_dbuf_in);
  517         if ((flags & FWRITE) != 0) {
  518                 midibuf_clear(&d->midi_dbuf_out);
  519                 midibuf_clear(&d->midi_dbuf_passthru);
  520         }
  521 
  522         mtx_unlock(&d->flagqueue_mtx);
  523 
  524         if (d->open == NULL)
  525                 ret = 0;
  526         else
  527                 ret = d->open(i_dev, flags, mode, td);
  528 
  529         mtx_lock(&d->flagqueue_mtx);
  530 
  531         /* Begin recording if nonblocking. */
  532         if ((d->flags & (MIDI_F_READING | MIDI_F_NBIO)) == MIDI_F_NBIO && (d->fflags & FREAD) != 0)
  533         d->callback(d, MIDI_CB_START | MIDI_CB_RD);
  534 
  535         mtx_unlock(&d->flagqueue_mtx);
  536 
  537         MIDI_DEBUG(printf("midi_open: opened.\n"));
  538 
  539         return (ret);
  540 }
  541 
  542 int
  543 midi_close(dev_t i_dev, int flags, int mode, struct thread *td)
  544 {
  545         int dev, unit, ret;
  546         mididev_info *d;
  547 
  548         dev = minor(i_dev);
  549         d = get_mididev_info(i_dev, &unit);
  550 
  551         MIDI_DEBUG(printf("midi_close: unit %d.\n", unit));
  552 
  553         if (d == NULL)
  554                 return (ENXIO);
  555 
  556         mtx_lock(&d->flagqueue_mtx);
  557 
  558         /* Stop recording and playing. */
  559         if ((d->flags & MIDI_F_READING) != 0)
  560                 d->callback(d, MIDI_CB_ABORT | MIDI_CB_RD);
  561         if ((d->flags & MIDI_F_WRITING) != 0)
  562                 d->callback(d, MIDI_CB_ABORT | MIDI_CB_WR);
  563 
  564         /* Clear the queues. */
  565         if ((d->fflags & FREAD) != 0)
  566                 midibuf_clear(&d->midi_dbuf_in);
  567         if ((d->fflags & FWRITE) != 0) {
  568                 midibuf_clear(&d->midi_dbuf_out);
  569                 midibuf_clear(&d->midi_dbuf_passthru);
  570         }
  571 
  572         /* Stop playing and unmark this device busy. */
  573         d->flags &= ~MIDI_F_BUSY;
  574         d->fflags = 0;
  575 
  576         device_unbusy(d->dev);
  577 
  578         mtx_unlock(&d->flagqueue_mtx);
  579 
  580         if (d->close == NULL)
  581                 ret = 0;
  582         else
  583                 ret = d->close(i_dev, flags, mode, td);
  584 
  585         MIDI_DEBUG(printf("midi_close: closed.\n"));
  586 
  587         return (ret);
  588 }
  589 
  590 int
  591 midi_read(dev_t i_dev, struct uio * buf, int flag)
  592 {
  593         int dev, unit, len, lenr, ret;
  594         mididev_info *d ;
  595         u_char *uiobuf;
  596 
  597         dev = minor(i_dev);
  598 
  599         d = get_mididev_info(i_dev, &unit);
  600         MIDI_DEBUG(printf("midi_read: unit %d, resid %d.\n", unit, buf->uio_resid));
  601 
  602         if (d == NULL)
  603                 return (ENXIO);
  604 
  605         ret = 0;
  606 
  607         len = buf->uio_resid;
  608         lenr = 0;
  609 
  610         uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
  611         if (uiobuf == NULL)
  612                 return (ENOMEM);
  613 
  614         mtx_lock(&d->flagqueue_mtx);
  615 
  616         /* Begin recording. */
  617         d->callback(d, MIDI_CB_START | MIDI_CB_RD);
  618 
  619         /* Have we got the data to read? */
  620         if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_in.rl == 0)
  621                 ret = EAGAIN;
  622         else {
  623                 if ((d->flags & MIDI_F_NBIO) != 0 && len > d->midi_dbuf_in.rl)
  624                         len = d->midi_dbuf_in.rl;
  625                 ret = midibuf_seqread(&d->midi_dbuf_in, uiobuf, len, &lenr,
  626                                       d->callback, d, MIDI_CB_START | MIDI_CB_RD,
  627                                       &d->flagqueue_mtx);
  628         }
  629 
  630         mtx_unlock(&d->flagqueue_mtx);
  631 
  632         if (lenr > 0)
  633                 ret = uiomove(uiobuf, lenr, buf);
  634 
  635         free(uiobuf, M_DEVBUF);
  636 
  637         MIDI_DEBUG(printf("midi_read: ret %d, resid %d.\n", ret, buf->uio_resid));
  638 
  639         return (ret);
  640 }
  641 
  642 int
  643 midi_write(dev_t i_dev, struct uio * buf, int flag)
  644 {
  645         int dev, unit, len, len2, lenw, ret;
  646         mididev_info *d;
  647         u_char *uiobuf;
  648 
  649         dev = minor(i_dev);
  650         d = get_mididev_info(i_dev, &unit);
  651 
  652         MIDI_DEBUG(printf("midi_write: unit %d.\n", unit));
  653 
  654         if (d == NULL)
  655                 return (ENXIO);
  656 
  657         ret = 0;
  658 
  659         len = buf->uio_resid;
  660         lenw = 0;
  661 
  662         uiobuf = (u_char *)malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
  663         if (uiobuf == NULL)
  664                 return (ENOMEM);
  665 
  666         ret = uiomove(uiobuf, len, buf);
  667         if (ret != 0) {
  668                 free(uiobuf, M_DEVBUF);
  669                 return (ret);
  670         }
  671 
  672         mtx_lock(&d->flagqueue_mtx);
  673 
  674         /* Have we got the data to write? */
  675         if ((d->flags & MIDI_F_NBIO) != 0 && d->midi_dbuf_out.fl == 0) {
  676                 /* Begin playing. */
  677                 d->callback(d, MIDI_CB_START | MIDI_CB_WR);
  678                 ret = EAGAIN;
  679         } else {
  680                 len2 = len;
  681                 if ((d->flags & MIDI_F_NBIO) != 0 && len2 > d->midi_dbuf_out.fl)
  682                         len2 = d->midi_dbuf_out.fl;
  683                 ret = midibuf_seqwrite(&d->midi_dbuf_out, uiobuf, len2, &lenw,
  684                                        d->callback, d, MIDI_CB_START | MIDI_CB_WR,
  685                                        &d->flagqueue_mtx);
  686         }
  687 
  688         mtx_unlock(&d->flagqueue_mtx);
  689 
  690         free(uiobuf, M_DEVBUF);
  691         buf->uio_resid = len - lenw;
  692 
  693         return (ret);
  694 }
  695 
  696 /*
  697  * generic midi ioctl. Functions of the default driver can be
  698  * overridden by the device-specific ioctl call.
  699  * If a device-specific call returns ENOSYS (Function not implemented),
  700  * the default driver is called. Otherwise, the returned value
  701  * is passed up.
  702  *
  703  * The default handler, for many parameters, sets the value in the
  704  * descriptor, sets MIDI_F_INIT, and calls the callback function with
  705  * reason INIT. If successful, the callback returns 1 and the caller
  706  * can update the parameter.
  707  */
  708 
  709 int
  710 midi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  711 {
  712         int ret = ENOSYS, dev, unit;
  713         mididev_info *d;
  714         struct snd_size *sndsize;
  715         snd_sync_parm *sp;
  716 
  717         dev = minor(i_dev);
  718         d = get_mididev_info(i_dev, &unit);
  719 
  720         if (d == NULL)
  721                 return (ENXIO);
  722 
  723         if (d->ioctl)
  724                 ret = d->ioctl(i_dev, cmd, arg, mode, td);
  725         if (ret != ENOSYS)
  726                 return ret;
  727 
  728         /*
  729          * pass control to the default ioctl handler. Set ret to 0 now.
  730          */
  731         ret = 0;
  732 
  733         MIDI_DEBUG(printf("midi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl)));
  734 
  735         /*
  736          * all routines are called with int. blocked. Make sure that
  737          * ints are re-enabled when calling slow or blocking functions!
  738          */
  739         switch(cmd) {
  740 
  741                 /*
  742                  * we start with the new ioctl interface.
  743                  */
  744         case AIONWRITE: /* how many bytes can write ? */
  745                 mtx_lock(&d->flagqueue_mtx);
  746                 *(int *)arg = d->midi_dbuf_out.fl;
  747                 mtx_unlock(&d->flagqueue_mtx);
  748                 MIDI_DEBUG(printf("midi_ioctl: fl %d.\n", *(int *)arg));
  749                 break;
  750 
  751         case AIOSSIZE:     /* set the current blocksize */
  752                 sndsize = (struct snd_size *)arg;
  753                 MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size));
  754                 mtx_lock(&d->flagqueue_mtx);
  755                 if (sndsize->play_size <= d->midi_dbuf_out.unit_size && sndsize->rec_size <= d->midi_dbuf_in.unit_size) {
  756                         d->midi_dbuf_out.blocksize = d->midi_dbuf_out.unit_size;
  757                         d->midi_dbuf_in.blocksize = d->midi_dbuf_in.unit_size;
  758                         sndsize->play_size = d->midi_dbuf_out.blocksize;
  759                         sndsize->rec_size = d->midi_dbuf_in.blocksize;
  760                         d->flags &= ~MIDI_F_HAS_SIZE;
  761                         mtx_unlock(&d->flagqueue_mtx);
  762                 }
  763                 else {
  764                         if (sndsize->play_size > d->midi_dbuf_out.bufsize / 4)
  765                                 sndsize->play_size = d->midi_dbuf_out.bufsize / 4;
  766                         if (sndsize->rec_size > d->midi_dbuf_in.bufsize / 4)
  767                                 sndsize->rec_size = d->midi_dbuf_in.bufsize / 4;
  768                         /* Round up the size to the multiple of EV_SZ. */
  769                         d->midi_dbuf_out.blocksize =
  770                             ((sndsize->play_size + d->midi_dbuf_out.unit_size - 1)
  771                              / d->midi_dbuf_out.unit_size) * d->midi_dbuf_out.unit_size;
  772                         d->midi_dbuf_in.blocksize =
  773                             ((sndsize->rec_size + d->midi_dbuf_in.unit_size - 1)
  774                              / d->midi_dbuf_in.unit_size) * d->midi_dbuf_in.unit_size;
  775                         sndsize->play_size = d->midi_dbuf_out.blocksize;
  776                         sndsize->rec_size = d->midi_dbuf_in.blocksize;
  777                         d->flags |= MIDI_F_HAS_SIZE;
  778                         mtx_unlock(&d->flagqueue_mtx);
  779                 }
  780 
  781                 ret = 0;
  782                 break;
  783 
  784         case AIOGSIZE:  /* get the current blocksize */
  785                 sndsize = (struct snd_size *)arg;
  786                 mtx_lock(&d->flagqueue_mtx);
  787                 sndsize->play_size = d->midi_dbuf_out.blocksize;
  788                 sndsize->rec_size = d->midi_dbuf_in.blocksize;
  789                 mtx_unlock(&d->flagqueue_mtx);
  790                 MIDI_DEBUG(printf("midi_ioctl: play %d, rec %d.\n", sndsize->play_size, sndsize->rec_size));
  791 
  792                 ret = 0;
  793                 break;
  794 
  795         case AIOSTOP:
  796                 mtx_lock(&d->flagqueue_mtx);
  797                 if (*(int *)arg == AIOSYNC_PLAY) /* play */
  798                         *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
  799                 else if (*(int *)arg == AIOSYNC_CAPTURE)
  800                         *(int *)arg = d->callback(d, MIDI_CB_STOP | MIDI_CB_RD);
  801                 else {
  802                         MIDI_DEBUG(printf("midi_ioctl: bad channel 0x%x.\n", *(int *)arg));
  803                         *(int *)arg = 0 ;
  804                 }
  805                 mtx_unlock(&d->flagqueue_mtx);
  806                 break ;
  807 
  808         case AIOSYNC:
  809                 sp = (snd_sync_parm *)arg;
  810                 MIDI_DEBUG(printf("midi_ioctl: unimplemented, chan 0x%03lx pos %lu.\n",
  811                            sp->chan,
  812                            sp->pos));
  813                 break;
  814                 /*
  815                  * here follow the standard ioctls (filio.h etc.)
  816                  */
  817         case FIONREAD: /* get # bytes to read */
  818                 mtx_lock(&d->flagqueue_mtx);
  819                 *(int *)arg = d->midi_dbuf_in.rl;
  820                 mtx_unlock(&d->flagqueue_mtx);
  821                 MIDI_DEBUG(printf("midi_ioctl: rl %d.\n", *(int *)arg));
  822                 break;
  823 
  824         case FIOASYNC: /*set/clear async i/o */
  825                 MIDI_DEBUG(printf("FIOASYNC\n"));
  826                     break;
  827 
  828         case FIONBIO: /* set/clear non-blocking i/o */
  829                 mtx_lock(&d->flagqueue_mtx);
  830                 if (*(int *)arg == 0)
  831                         d->flags &= ~MIDI_F_NBIO ;
  832                 else
  833                         d->flags |= MIDI_F_NBIO ;
  834                 mtx_unlock(&d->flagqueue_mtx);
  835                 MIDI_DEBUG(printf("midi_ioctl: arg %d.\n", *(int *)arg));
  836                 break ;
  837 
  838         case MIOSPASSTHRU: /* set/clear passthru */
  839                 mtx_lock(&d->flagqueue_mtx);
  840                 if (*(int *)arg == 0)
  841                         d->flags &= ~MIDI_F_PASSTHRU ;
  842                 else
  843                         d->flags |= MIDI_F_PASSTHRU ;
  844 
  845                 /* Init the queue. */
  846                 midibuf_clear(&d->midi_dbuf_passthru);
  847 
  848                 mtx_unlock(&d->flagqueue_mtx);
  849                 MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg));
  850 
  851                 /* FALLTHROUGH */
  852         case MIOGPASSTHRU: /* get passthru */
  853                 mtx_lock(&d->flagqueue_mtx);
  854                 if ((d->flags & MIDI_F_PASSTHRU) != 0)
  855                         *(int *)arg = 1;
  856                 else
  857                         *(int *)arg = 0;
  858                 mtx_unlock(&d->flagqueue_mtx);
  859                 MIDI_DEBUG(printf("midi_ioctl: passthru %d.\n", *(int *)arg));
  860                 break;
  861 
  862         default:
  863                 MIDI_DEBUG(printf("midi_ioctl: default ioctl midi%d subdev %d fn 0x%08lx fail\n",
  864                                   unit, dev & 0xf, cmd));
  865                 ret = EINVAL;
  866                 break ;
  867         }
  868         return ret ;
  869 }
  870 
  871 int
  872 midi_poll(dev_t i_dev, int events, struct thread *td)
  873 {
  874         int unit, dev, ret, lim;
  875         mididev_info *d;
  876 
  877         dev = minor(i_dev);
  878         d = get_mididev_info(i_dev, &unit);
  879 
  880         MIDI_DEBUG(printf("midi_poll: unit %d.\n", unit));
  881 
  882         if (d == NULL)
  883                 return (ENXIO);
  884 
  885         ret = 0;
  886 
  887         mtx_lock(&d->flagqueue_mtx);
  888 
  889         /* Look up the apropriate queue and select it. */
  890         if ((events & (POLLOUT | POLLWRNORM)) != 0) {
  891                 /* Start playing. */
  892                 d->callback(d, MIDI_CB_START | MIDI_CB_WR);
  893 
  894                 /* Find out the boundary. */
  895                 if ((d->flags & MIDI_F_HAS_SIZE) != 0)
  896                         lim = d->midi_dbuf_out.blocksize;
  897                 else
  898                         lim = d->midi_dbuf_out.unit_size;
  899                 if (d->midi_dbuf_out.fl < lim)
  900                         /* No enough space, record select. */
  901                         selrecord(td, &d->midi_dbuf_out.sel);
  902                 else
  903                         /* We can write now. */
  904                         ret |= events & (POLLOUT | POLLWRNORM);
  905         }
  906         if ((events & (POLLIN | POLLRDNORM)) != 0) {
  907                 /* Start recording. */
  908                 d->callback(d, MIDI_CB_START | MIDI_CB_RD);
  909 
  910                 /* Find out the boundary. */
  911                 if ((d->flags & MIDI_F_HAS_SIZE) != 0)
  912                         lim = d->midi_dbuf_in.blocksize;
  913                 else
  914                         lim = d->midi_dbuf_in.unit_size;
  915                 if (d->midi_dbuf_in.rl < lim)
  916                         /* No data ready, record select. */
  917                         selrecord(td, &d->midi_dbuf_in.sel);
  918                 else
  919                         /* We can write now. */
  920                         ret |= events & (POLLIN | POLLRDNORM);
  921         }
  922 
  923         mtx_unlock(&d->flagqueue_mtx);
  924 
  925         return (ret);
  926 }
  927 
  928 void
  929 midi_intr(mididev_info *d)
  930 {
  931         if (d->intr != NULL)
  932                 d->intr(d->intrarg, d);
  933 }
  934 
  935 /* Flush the output queue. */
  936 #define MIDI_SYNC_TIMEOUT 1
  937 int
  938 midi_sync(mididev_info *d)
  939 {
  940         int i, rl;
  941 
  942         mtx_assert(&d->flagqueue_mtx, MA_OWNED);
  943 
  944         MIDI_DEBUG(printf("midi_sync: unit %d.\n", d->unit));
  945 
  946         while (d->midi_dbuf_out.rl > 0) {
  947                 if ((d->flags & MIDI_F_WRITING) == 0)
  948                         d->callback(d, MIDI_CB_START | MIDI_CB_WR);
  949                 rl = d->midi_dbuf_out.rl;
  950                 i = cv_timedwait_sig(&d->midi_dbuf_out.cv_out,
  951                                      &d->flagqueue_mtx,
  952                                      (d->midi_dbuf_out.bufsize * 10 * hz / 38400)
  953                                      + MIDI_SYNC_TIMEOUT * hz);
  954                 if (i == EINTR || i == ERESTART) {
  955                         if (i == EINTR)
  956                                 d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
  957                         return (i);
  958                 }
  959                 if (i == EWOULDBLOCK && rl == d->midi_dbuf_out.rl) {
  960                         /* A queue seems to be stuck up. Give up and clear the queue. */
  961                         d->callback(d, MIDI_CB_STOP | MIDI_CB_WR);
  962                         midibuf_clear(&d->midi_dbuf_out);
  963                         return (0);
  964                 }
  965         }
  966 
  967         return 0;
  968 }
  969 
  970 /*
  971  * These handle the status message of the midi drivers.
  972  */
  973 
  974 int
  975 midistat_open(dev_t i_dev, int flags, int mode, struct thread *td)
  976 {
  977         if (midistatbusy)
  978                 return (EBUSY);
  979 
  980         bzero(midistatbuf, sizeof(midistatbuf));
  981         midistatptr = 0;
  982         if (midi_initstatus(midistatbuf, sizeof(midistatbuf) - 1))
  983                 return (ENOMEM);
  984 
  985         midistatbusy = 1;
  986 
  987         return (0);
  988 }
  989 
  990 int
  991 midistat_close(dev_t i_dev, int flags, int mode, struct thread *td)
  992 {
  993         midistatbusy = 0;
  994 
  995         return (0);
  996 }
  997 
  998 int
  999 midistat_read(dev_t i_dev, struct uio * buf, int flag)
 1000 {
 1001         return midi_readstatus(midistatbuf, &midistatptr, buf);
 1002 }
 1003 
 1004 /*
 1005  * finally, some "libraries"
 1006  */
 1007 
 1008 /* Inits the buffer for /dev/midistat. */
 1009 static int
 1010 midi_initstatus(char *buf, int size)
 1011 {
 1012         int i, p;
 1013         device_t dev;
 1014         mididev_info *md;
 1015 
 1016         p = 0;
 1017         p += snprintf(buf, size, "FreeBSD Midi Driver (newmidi) %s %s\nInstalled devices:\n", __DATE__, __TIME__);
 1018         for (i = 0 ; i < mididev_info_number() ; i++) {
 1019                 md = get_mididev_info_unit(i);
 1020                 if (!MIDICONFED(md))
 1021                         continue;
 1022                 dev = devclass_get_device(midi_devclass, i);
 1023                 if (p < size)
 1024                         p += snprintf(&buf[p], size - p, "midi%d: <%s> %s\n", i, device_get_desc(dev), md->midistat);
 1025                 else
 1026                         return (1);
 1027         }
 1028 
 1029         return (0);
 1030 }
 1031 
 1032 /* Reads the status message. */
 1033 static int
 1034 midi_readstatus(char *buf, int *ptr, struct uio *uio)
 1035 {
 1036         int len;
 1037 
 1038         len = min(uio->uio_resid, strlen(&buf[*ptr]));
 1039         if (len > 0) {
 1040                 uiomove(&buf[*ptr], len, uio);
 1041                 *ptr += len;
 1042         }
 1043 
 1044         return (0);
 1045 }
 1046 
 1047 char
 1048 *midi_cmdname(int cmd, midi_cmdtab *tab)
 1049 {
 1050         while (tab->name != NULL) {
 1051                 if (cmd == tab->cmd)
 1052                         return (tab->name);
 1053                 tab++;
 1054         }
 1055 
 1056         return ("unknown");
 1057 }

Cache object: de765b0a7e5859fceca71e869e49b5ea


[ 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.