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/isa/gusmidi.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  * GUS midi interface driver.
    3  * Based on the newmidi MPU401 driver.
    4  *
    5  * Copyright (c) 1999 Ville-Pertti Keinonen
    6  * Copyright by Hannu Savolainen 1993
    7  * 
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions are
   10  * met: 1. Redistributions of source code must retain the above copyright
   11  * notice, this list of conditions and the following disclaimer. 2.
   12  * Redistributions in binary form must reproduce the above copyright notice,
   13  * this list of conditions and the following disclaimer in the documentation
   14  * and/or other materials provided with the distribution.
   15  * 
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
   17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  * 
   28  * Modified: Riccardo Facchetti  24 Mar 1995 - Added the Audio Excel DSP 16
   29  * initialization routine.
   30  *
   31  * Ported to the new Audio Driver by Luigi Rizzo:
   32  * (C) 1999 Seigo Tanimura <tanimura@r.dl.itc.u-tokyo.ac.jp>
   33  *
   34  * $FreeBSD: releng/5.2/sys/dev/sound/isa/gusmidi.c 93818 2002-04-04 21:03:38Z jhb $
   35  *
   36  */
   37 
   38 #include <dev/sound/midi/midi.h>
   39 
   40 #include <dev/sound/chip.h>
   41 #include <machine/cpufunc.h>
   42 
   43 static devclass_t midi_devclass;
   44 
   45 extern synthdev_info midisynth_op_desc;
   46 
   47 /* These are the synthesizer and the midi interface information. */
   48 static struct synth_info gusmidi_synthinfo = {
   49         "GUS MIDI",
   50         0,
   51         SYNTH_TYPE_MIDI,
   52         0,
   53         0,
   54         128,
   55         128,
   56         128,
   57         SYNTH_CAP_INPUT,
   58 };
   59 
   60 static struct midi_info gusmidi_midiinfo = {
   61         "GUS MIDI",
   62         0,
   63         0,
   64         0,
   65 };
   66 
   67 #define MIDICTL_MASTER_RESET    0x03
   68 #define MIDICTL_TX_IRQ_EN       0x20
   69 #define MIDICTL_RX_IRQ_EN       0x80
   70 
   71 #define MIDIST_RXFULL           0x01
   72 #define MIDIST_TXDONE           0x02
   73 #define MIDIST_ERR_FR           0x10
   74 #define MIDIST_ERR_OVR          0x20
   75 #define MIDIST_INTR_PEND        0x80
   76 
   77 #define PORT_CTL                0
   78 #define PORT_ST                 0
   79 #define PORT_TX                 1
   80 #define PORT_RX                 1
   81 
   82 /*
   83  * These functions goes into gusmidi_op_desc to get called
   84  * from sound.c.
   85  */
   86 
   87 static int gusmidi_probe(device_t dev);
   88 static int gusmidi_attach(device_t dev);
   89 
   90 static d_open_t gusmidi_open;
   91 static d_ioctl_t gusmidi_ioctl;
   92 driver_intr_t gusmidi_intr;
   93 static midi_callback_t gusmidi_callback;
   94 
   95 /* Here is the parameter structure per a device. */
   96 struct gusmidi_softc {
   97         device_t dev; /* device information */
   98         mididev_info *devinfo; /* midi device information */
   99 
  100         struct mtx mtx; /* Mutex to protect the device. */
  101 
  102         struct resource *io; /* Base of io port */
  103         int io_rid; /* Io resource ID */
  104         struct resource *irq; /* Irq */
  105         int irq_rid; /* Irq resource ID */
  106         void *ih; /* Interrupt cookie */
  107 
  108         int ctl;        /* Control bits.  */
  109 };
  110 
  111 typedef struct gusmidi_softc *sc_p;
  112 
  113 /* These functions are local. */
  114 static int gusmidi_init(device_t dev);
  115 static int gusmidi_allocres(sc_p scp, device_t dev);
  116 static void gusmidi_releaseres(sc_p scp, device_t dev);
  117 static void gusmidi_startplay(sc_p scp);
  118 static void gusmidi_xmit(sc_p scp);
  119 static u_int gusmidi_readport(sc_p scp, int off);
  120 static void gusmidi_writeport(sc_p scp, int off, u_int8_t value);
  121 
  122 /*
  123  * This is the device descriptor for the midi device.
  124  */
  125 static mididev_info gusmidi_op_desc = {
  126         "GUS midi",
  127 
  128         SNDCARD_GUS,
  129 
  130         gusmidi_open,
  131         NULL,
  132         gusmidi_ioctl,
  133 
  134         gusmidi_callback,
  135 
  136         MIDI_BUFFSIZE, /* Queue Length */
  137 
  138         0, /* XXX This is not an *audio* device! */
  139 };
  140 
  141 static int
  142 gusmidi_probe(device_t dev)
  143 {
  144         char *s;
  145         sc_p scp;
  146         struct sndcard_func *func;
  147 
  148         /* The parent device has already been probed. */
  149 
  150         func = device_get_ivars(dev);
  151         if (func == NULL || func->func != SCF_MIDI)
  152                 return (ENXIO);
  153 
  154         s = "GUS Midi Interface";
  155 
  156         scp = device_get_softc(dev);
  157         bzero(scp, sizeof(*scp));
  158         scp->io_rid = 1;
  159         scp->irq_rid = 0;
  160 #if notdef
  161         ret = mpu_probe2(dev);
  162         if (ret != 0)
  163                 return (ret);
  164 #endif /* notdef */
  165         device_set_desc(dev, s);
  166         return (0);
  167 }
  168 
  169 static int
  170 gusmidi_attach(device_t dev)
  171 {
  172         sc_p scp;
  173 
  174         scp = device_get_softc(dev);
  175 
  176         /* Allocate the resources, switch to uart mode. */
  177         if (gusmidi_allocres(scp, dev)) {
  178                 gusmidi_releaseres(scp, dev);
  179                 return (ENXIO);
  180         }
  181 
  182         gusmidi_init(dev);
  183 
  184         return (0);
  185 }
  186 
  187 static int
  188 gusmidi_init(device_t dev)
  189 {
  190         sc_p scp;
  191         mididev_info *devinfo;
  192 
  193         scp = device_get_softc(dev);
  194 
  195         /* Fill the softc. */
  196         scp->dev = dev;
  197         mtx_init(&scp->mtx, "gusmid", NULL, MTX_DEF);
  198         scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &gusmidi_op_desc, &midisynth_op_desc);
  199 
  200         /* Fill the midi info. */
  201         if (scp->irq != NULL)
  202                 snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
  203                          (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
  204         else
  205                 snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x",
  206                          (u_int)rman_get_start(scp->io));
  207 
  208         midiinit(devinfo, dev);
  209 
  210         bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, gusmidi_intr, scp,
  211             &scp->ih);
  212 
  213         return (0);
  214 }
  215 
  216 static int
  217 gusmidi_open(dev_t i_dev, int flags, int mode, struct thread *td)
  218 {
  219         sc_p scp;
  220         mididev_info *devinfo;
  221         int unit;
  222 
  223         unit = MIDIUNIT(i_dev);
  224 
  225         devinfo = get_mididev_info(i_dev, &unit);
  226         if (devinfo == NULL) {
  227                 MIDI_DEBUG(printf("gusmidi_open: unit %d is not configured.\n", unit));
  228                 return (ENXIO);
  229         }
  230         scp = devinfo->softc;
  231 
  232         mtx_lock(&scp->mtx);
  233 
  234         gusmidi_writeport(scp, PORT_CTL, MIDICTL_MASTER_RESET);
  235         DELAY(100);
  236 
  237         gusmidi_writeport(scp, PORT_CTL, scp->ctl);
  238 
  239         mtx_unlock(&scp->mtx);
  240 
  241         return (0);
  242 }
  243 
  244 static int
  245 gusmidi_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  246 {
  247         sc_p scp;
  248         mididev_info *devinfo;
  249         int unit;
  250         struct synth_info *synthinfo;
  251         struct midi_info *midiinfo;
  252 
  253         unit = MIDIUNIT(i_dev);
  254 
  255         MIDI_DEBUG(printf("gusmidi_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl)));
  256 
  257         devinfo = get_mididev_info(i_dev, &unit);
  258         if (devinfo == NULL) {
  259                 MIDI_DEBUG(printf("gusmidi_ioctl: unit %d is not configured.\n", unit));
  260                 return (ENXIO);
  261         }
  262         scp = devinfo->softc;
  263 
  264         switch (cmd) {
  265         case SNDCTL_SYNTH_INFO:
  266                 synthinfo = (struct synth_info *)arg;
  267                 if (synthinfo->device != unit)
  268                         return (ENXIO);
  269                 bcopy(&gusmidi_synthinfo, synthinfo, sizeof(gusmidi_synthinfo));
  270                 synthinfo->device = unit;
  271                 return (0);
  272                 break;
  273         case SNDCTL_MIDI_INFO:
  274                 midiinfo = (struct midi_info *)arg;
  275                 if (midiinfo->device != unit)
  276                         return (ENXIO);
  277                 bcopy(&gusmidi_midiinfo, midiinfo, sizeof(gusmidi_midiinfo));
  278                 midiinfo->device = unit;
  279                 return (0);
  280                 break;
  281         default:
  282                 return (ENOSYS);
  283         }
  284         /* NOTREACHED */
  285         return (EINVAL);
  286 }
  287 
  288 void
  289 gusmidi_intr(void *arg)
  290 {
  291         sc_p scp;
  292         u_char c;
  293         mididev_info *devinfo;
  294         int stat, did_something, leni;
  295 
  296         scp = (sc_p)arg;
  297         devinfo = scp->devinfo;
  298 
  299         /* XXX No framing/overrun checks...  */
  300         mtx_lock(&devinfo->flagqueue_mtx);
  301         mtx_lock(&scp->mtx);
  302 
  303         do {
  304                 stat = gusmidi_readport(scp, PORT_ST);
  305                 did_something = 0;
  306                 if (stat & MIDIST_RXFULL) {
  307                         c = gusmidi_readport(scp, PORT_RX);
  308                         mtx_unlock(&scp->mtx);
  309                         if ((devinfo->flags & MIDI_F_PASSTHRU) &&
  310                             (!(devinfo->flags & MIDI_F_BUSY) ||
  311                              !(devinfo->fflags & FWRITE))) {
  312                                 midibuf_input_intr(&devinfo->midi_dbuf_passthru,
  313                                     &c, sizeof c, &leni);
  314                                 devinfo->callback(devinfo,
  315                                     MIDI_CB_START | MIDI_CB_WR);
  316                         }
  317                         if ((devinfo->flags & MIDI_F_READING) && c != 0xfe) {
  318                                 midibuf_input_intr(&devinfo->midi_dbuf_in,
  319                                     &c, sizeof c, &leni);
  320                         }
  321                         did_something = 1;
  322                 } else
  323                         mtx_unlock(&scp->mtx);
  324                 if (stat & MIDIST_TXDONE) {
  325                         if (devinfo->flags & MIDI_F_WRITING) {
  326                                 gusmidi_xmit(scp);
  327                                 did_something = 1;
  328                                 mtx_lock(&scp->mtx);
  329                         } else if (scp->ctl & MIDICTL_TX_IRQ_EN) {
  330                                 /* This shouldn't happen.  */
  331                                 mtx_lock(&scp->mtx);
  332                                 scp->ctl &= ~MIDICTL_TX_IRQ_EN; 
  333                                 gusmidi_writeport(scp, PORT_CTL, scp->ctl);
  334                         }
  335                 } else
  336                         mtx_lock(&scp->mtx);
  337         } while (did_something != 0);
  338 
  339         mtx_unlock(&scp->mtx);
  340         mtx_unlock(&devinfo->flagqueue_mtx);
  341 
  342         /* Invoke the upper layer. */
  343         midi_intr(devinfo);
  344 }
  345 
  346 static int
  347 gusmidi_callback(void *di, int reason)
  348 {
  349         int unit;
  350         sc_p scp;
  351         mididev_info *d;
  352 
  353         d = (mididev_info *)di;
  354 
  355         mtx_assert(&d->flagqueue_mtx, MA_OWNED);
  356 
  357         if (d == NULL) {
  358                 MIDI_DEBUG(printf("gusmidi_callback: device not configured.\n"));
  359                 return (ENXIO);
  360         }
  361 
  362         unit = d->unit;
  363         scp = d->softc;
  364 
  365         switch (reason & MIDI_CB_REASON_MASK) {
  366         case MIDI_CB_START:
  367                 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0) {
  368                         /* Begin recording. */
  369                         d->flags |= MIDI_F_READING;
  370                         mtx_lock(&scp->mtx);
  371                         scp->ctl |= MIDICTL_RX_IRQ_EN;
  372                         gusmidi_writeport(scp, PORT_CTL, scp->ctl);
  373                         mtx_unlock(&scp->mtx);
  374                 }
  375                 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
  376                         /* Start playing. */
  377                         gusmidi_startplay(scp);
  378                 break;
  379         case MIDI_CB_STOP:
  380         case MIDI_CB_ABORT:
  381                 mtx_lock(&scp->mtx);
  382                 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0) {
  383                         /* Stop recording. */
  384                         d->flags &= ~MIDI_F_READING;
  385                         scp->ctl &= ~MIDICTL_RX_IRQ_EN;
  386                 }
  387                 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0) {
  388                         /* Stop Playing. */
  389                         d->flags &= ~MIDI_F_WRITING;
  390                         scp->ctl &= ~MIDICTL_TX_IRQ_EN;
  391                 }
  392                 gusmidi_writeport(scp, PORT_CTL, scp->ctl);
  393                 mtx_unlock(&scp->mtx);
  394                 break;
  395         }
  396 
  397         return (0);
  398 }
  399 
  400 /*
  401  * The functions below here are the libraries for the above ones.
  402  */
  403 
  404 /*
  405  * Starts to play the data in the output queue.
  406  */
  407 static void
  408 gusmidi_startplay(sc_p scp)
  409 {
  410         mididev_info *devinfo;
  411 
  412         devinfo = scp->devinfo;
  413 
  414         mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
  415 
  416         /* Can we play now? */
  417         if (devinfo->midi_dbuf_out.rl == 0)
  418                 return;
  419 
  420         devinfo->flags |= MIDI_F_WRITING;
  421         mtx_lock(&scp->mtx);
  422         scp->ctl |= MIDICTL_TX_IRQ_EN;
  423         mtx_unlock(&scp->mtx);
  424 }
  425 
  426 static void
  427 gusmidi_xmit(sc_p scp)
  428 {
  429         register mididev_info *devinfo;
  430         register midi_dbuf *dbuf;
  431         u_char c;
  432         int leno;
  433 
  434         devinfo = scp->devinfo;
  435 
  436         mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
  437 
  438         /* See which source to use. */
  439         if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
  440                 dbuf = &devinfo->midi_dbuf_out;
  441         else
  442                 dbuf = &devinfo->midi_dbuf_passthru;
  443 
  444         /* Transmit the data in the queue. */
  445         while (devinfo->flags & MIDI_F_WRITING) {
  446                 /* Do we have the data to transmit? */
  447                 if (dbuf->rl == 0) {
  448                         /* Stop playing. */
  449                         devinfo->flags &= ~MIDI_F_WRITING;
  450                         mtx_lock(&scp->mtx);
  451                         scp->ctl &= ~MIDICTL_TX_IRQ_EN;
  452                         gusmidi_writeport(scp, PORT_CTL, scp->ctl);
  453                         mtx_unlock(&scp->mtx);
  454                         break;
  455                 } else {
  456                         mtx_lock(&scp->mtx);
  457                         if (gusmidi_readport(scp, PORT_ST) & MIDIST_TXDONE) {
  458                                 /* Send the data. */
  459                                 midibuf_output_intr(dbuf, &c, sizeof(c), &leno);
  460                                 gusmidi_writeport(scp, PORT_TX, c);
  461                                 /* We are playing now. */
  462                         } else {
  463                                 mtx_unlock(&scp->mtx);
  464                                 break;
  465                         }
  466                         mtx_unlock(&scp->mtx);
  467                 }
  468         }
  469 }
  470 
  471 /* Reads from a port. */
  472 static u_int
  473 gusmidi_readport(sc_p scp, int off)
  474 {
  475         return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off) & 0xff;
  476 }
  477 
  478 /* Writes to a port. */
  479 static void
  480 gusmidi_writeport(sc_p scp, int off, u_int8_t value)
  481 {
  482         bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off, value);
  483 }
  484 
  485 /* Allocates resources. */
  486 static int
  487 gusmidi_allocres(sc_p scp, device_t dev)
  488 {
  489         if (scp->io == NULL) {
  490                 scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 2, RF_ACTIVE);
  491                 if (scp->io == NULL)
  492                         return (1);
  493         }
  494 #if notdef
  495         if (scp->irq == NULL && !(device_get_flags(dev) & MPU_DF_NO_IRQ)) {
  496 #else
  497         if (scp->irq == NULL) {
  498 #endif /* notdef */
  499                 scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
  500                 if (scp->irq == NULL)
  501                         return (1);
  502         }
  503 
  504         return (0);
  505 }
  506 
  507 /* Releases resources. */
  508 static void
  509 gusmidi_releaseres(sc_p scp, device_t dev)
  510 {
  511         if (scp->irq != NULL) {
  512                 bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
  513                 scp->irq = NULL;
  514         }
  515         if (scp->io != NULL) {
  516                 bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io);
  517                 scp->io = NULL;
  518         }
  519 }
  520 
  521 static device_method_t gusmidi_methods[] = {
  522         /* Device interface */
  523         DEVMETHOD(device_probe , gusmidi_probe ),
  524         DEVMETHOD(device_attach, gusmidi_attach),
  525 
  526         { 0, 0 },
  527 };
  528 
  529 driver_t gusmidi_driver = {
  530         "midi",
  531         gusmidi_methods,
  532         sizeof(struct gusmidi_softc),
  533 };
  534 
  535 DRIVER_MODULE(gusmidi, gusc, gusmidi_driver, midi_devclass, 0, 0);

Cache object: 0caa658987194edaf80f3af97cadcbcc


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