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/uartsio.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  * Copyright by George Hansper 1996
    3  *
    4  * Tue Jan 23 22:32:10 EST 1996 ghansper@daemon.apana.org.au
    5  *      added 16450/16550 support for standard serial-port UARTs
    6  *
    7  * Redistribution and use in source and binary forms, with or
    8  * without modification, are permitted provided that the following
    9  * conditions are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above
   13  *    copyright notice, this list of conditions and the following
   14  *    disclaimer in the documentation and/or other materials provided
   15  *    with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
   18  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
   21  * AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  *
   31  * Wed Apl  1 02:25:30 JST 1998 zinnia@jan.ne.jp
   32  *      ported to FreeBSD 2.2.5R-RELEASE
   33  *
   34  * Fri Apl  1 21:16:20 JST 1999 zinnia@jan.ne.jp
   35  *      ported to FreeBSD 3.1-STABLE
   36  *
   37  *
   38  * Ported to the new Audio Driver by Luigi Rizzo:
   39  * (C) 1999 Seigo Tanimura
   40  *
   41  * This is the 16550 midi uart driver for FreeBSD, based on the Luigi Sound Driver.
   42  * This handles io against /dev/midi, the midi {in, out}put event queues
   43  * and the event/message transmittion to/from a serial port interface.
   44  *
   45  * $FreeBSD: releng/5.1/sys/dev/sound/isa/uartsio.c 108064 2002-12-18 22:53:24Z semenu $
   46  *
   47  */
   48 
   49 #include <dev/sio/sioreg.h>
   50 #include <dev/ic/ns16550.h>
   51 #include <dev/sound/midi/midi.h>
   52 
   53 /* XXX What about a PCI uart? */
   54 #include <isa/isavar.h>
   55 
   56 static devclass_t midi_devclass;
   57 
   58 #ifndef DDB
   59 #undef DDB
   60 #define DDB(x)
   61 #endif /* DDB */
   62 
   63 #define TX_FIFO_SIZE 16
   64 
   65 extern synthdev_info midisynth_op_desc;
   66 
   67 /* These are the synthesizer and the midi interface information. */
   68 static struct synth_info uartsio_synthinfo = {
   69         "uart16550A MIDI",
   70         0,
   71         SYNTH_TYPE_MIDI,
   72         0,
   73         0,
   74         128,
   75         128,
   76         128,
   77         SYNTH_CAP_INPUT,
   78 };
   79 
   80 static struct midi_info uartsio_midiinfo = {
   81         "uart16550A MIDI",
   82         0,
   83         0,
   84         0,
   85 };
   86 
   87 /*
   88  * These functions goes into uartsio_op_desc to get called
   89  * from sound.c.
   90  */
   91 
   92 static int uartsio_probe(device_t dev);
   93 static int uartsio_attach(device_t dev);
   94 
   95 static d_ioctl_t uartsio_ioctl;
   96 static driver_intr_t uartsio_intr;
   97 static midi_callback_t uartsio_callback;
   98 
   99 /* Here is the parameter structure per a device. */
  100 struct uartsio_softc {
  101         device_t dev; /* device information */
  102         mididev_info *devinfo; /* midi device information */
  103 
  104         struct mtx mtx; /* Mutex to protect the device. */
  105 
  106         struct resource *io; /* Base of io port */
  107         int io_rid; /* Io resource ID */
  108         struct resource *irq; /* Irq */
  109         int irq_rid; /* Irq resource ID */
  110         void *ih; /* Interrupt cookie */
  111 
  112         int fflags; /* File flags */
  113 
  114         int has_fifo; /* TX/RX fifo in the uart */
  115         int tx_size; /* Size of TX on a transmission */
  116 
  117 };
  118 
  119 typedef struct uartsio_softc *sc_p;
  120 
  121 /* These functions are local. */
  122 static void uartsio_startplay(sc_p scp);
  123 static int uartsio_xmit(sc_p scp);
  124 static int uartsio_readport(sc_p scp, int off);
  125 static void uartsio_writeport(sc_p scp, int off, u_int8_t value);
  126 static int uartsio_allocres(sc_p scp, device_t dev);
  127 static void uartsio_releaseres(sc_p scp, device_t dev);
  128 
  129 /*
  130  * This is the device descriptor for the midi device.
  131  */
  132 static mididev_info uartsio_op_desc = {
  133         "16550 uart midi",
  134 
  135         SNDCARD_UART16550,
  136 
  137         NULL,
  138         NULL,
  139         uartsio_ioctl,
  140 
  141         uartsio_callback,
  142 
  143         MIDI_BUFFSIZE, /* Queue Length */
  144 
  145         0, /* XXX This is not an *audio* device! */
  146 };
  147 
  148 /*
  149  * Here are the main functions to interact to the user process.
  150  * These are called from snd* functions in sys/i386/isa/snd/sound.c.
  151  */
  152 
  153 static int
  154 uartsio_probe(device_t dev)
  155 {
  156         sc_p scp;
  157         int unit;
  158         u_char c;
  159 
  160         if (isa_get_logicalid(dev) != 0)
  161                 /* This is NOT a PnP device! */
  162                 return (ENXIO);
  163 
  164         scp = device_get_softc(dev);
  165         unit = device_get_unit(dev);
  166 
  167         device_set_desc(dev, uartsio_op_desc.name);
  168         bzero(scp, sizeof(*scp));
  169 
  170         scp->io_rid = 0;
  171         scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 8, RF_ACTIVE);
  172         if (scp->io == NULL)
  173                 return (ENXIO);
  174 
  175         MIDI_DEBUG(printf("uartsio%d: probing.\n", unit));
  176 
  177 /* Read the IER. The upper four bits should all be zero. */
  178         c = uartsio_readport(scp, com_ier);
  179         if ((c & 0xf0) != 0) {
  180                 uartsio_releaseres(scp, dev);
  181                 return (ENXIO);
  182         }
  183 
  184 /* Read the MSR. The upper three bits should all be zero. */
  185         c = uartsio_readport(scp, com_mcr);
  186         if ((c & 0xe0) != 0) {
  187                 uartsio_releaseres(scp, dev);
  188                 return (ENXIO);
  189         }
  190 
  191         /* XXX Do we need a loopback test? */
  192 
  193         MIDI_DEBUG(printf("uartsio%d: probed.\n", unit));
  194 
  195         return (0);
  196 }
  197 
  198 static int
  199 uartsio_attach(device_t dev)
  200 {
  201         sc_p scp;
  202         mididev_info *devinfo;
  203 
  204         scp = device_get_softc(dev);
  205 
  206         MIDI_DEBUG(printf("uartsio: attaching.\n"));
  207 
  208         /* Allocate resources. */
  209         if (uartsio_allocres(scp, dev)) {
  210                 uartsio_releaseres(scp, dev);
  211                 return (ENXIO);
  212         }
  213 
  214         /* See the size of the tx fifo. */
  215         uartsio_writeport(scp, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_RX_HIGH);
  216         if ((uartsio_readport(scp, com_iir) & IIR_FIFO_MASK) == FIFO_RX_HIGH) {
  217                 scp->has_fifo = 1;
  218                 scp->tx_size = TX_FIFO_SIZE;
  219                 MIDI_DEBUG(printf("uartsio: uart is 16550A, tx size is %d bytes.\n", scp->tx_size));
  220         } else {
  221                 scp->has_fifo = 0;
  222                 scp->tx_size = 1;
  223                 MIDI_DEBUG(printf("uartsio: uart is not 16550A.\n"));
  224         }
  225 
  226         /* Configure the uart. */
  227         uartsio_writeport(scp, com_cfcr, CFCR_DLAB); /* Latch the divisor. */
  228         uartsio_writeport(scp, com_dlbl, 0x03);
  229         uartsio_writeport(scp, com_dlbh, 0x00); /* We want a bitrate of 38.4kbps. */
  230         uartsio_writeport(scp, com_cfcr, CFCR_8BITS); /* We want 8bits, 1 stop bit, no parity. */
  231         uartsio_writeport(scp, com_mcr, MCR_IENABLE | MCR_RTS | MCR_DTR); /* Enable interrupt, set RTS and DTR. */
  232         uartsio_writeport(scp, com_ier, IER_ERXRDY | IER_ETXRDY | IER_EMSC | IER_ERLS); /* Give us an interrupt on RXRDY, TXRDY, MSC and RLS. */
  233         if (scp->has_fifo)
  234                 uartsio_writeport(scp, com_fifo, FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_RX_LOW); /* We use the fifo. */
  235         else
  236                 uartsio_writeport(scp, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST | FIFO_RX_LOW); /* We do not use the fifo. */
  237 
  238         /* Clear the gabage. */
  239         uartsio_readport(scp, com_lsr);
  240         uartsio_readport(scp, com_lsr);
  241         uartsio_readport(scp, com_iir);
  242         uartsio_readport(scp, com_data);
  243 
  244         /* Fill the softc. */
  245         scp->dev = dev;
  246         mtx_init(&scp->mtx, "siomid", NULL, MTX_DEF);
  247         scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &uartsio_op_desc, &midisynth_op_desc);
  248 
  249         /* Fill the midi info. */
  250         snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
  251                  (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
  252 
  253         midiinit(devinfo, dev);
  254 
  255         /* Now we can handle the interrupts. */
  256         bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, uartsio_intr, scp, &scp->ih);
  257 
  258         MIDI_DEBUG(printf("uartsio: attached.\n"));
  259 
  260         return (0);
  261 }
  262 
  263 static int
  264 uartsio_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  265 {
  266         sc_p scp;
  267         mididev_info *devinfo;
  268         int unit;
  269         struct synth_info *synthinfo;
  270         struct midi_info *midiinfo;
  271 
  272         unit = MIDIUNIT(i_dev);
  273 
  274         MIDI_DEBUG(printf("uartsio_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl)));
  275 
  276         devinfo = get_mididev_info(i_dev, &unit);
  277         if (devinfo == NULL) {
  278                 MIDI_DEBUG(printf("uartsio_ioctl: unit %d is not configured.\n", unit));
  279                 return (ENXIO);
  280         }
  281         scp = devinfo->softc;
  282 
  283         switch (cmd) {
  284         case SNDCTL_SYNTH_INFO:
  285                 synthinfo = (struct synth_info *)arg;
  286                 if (synthinfo->device != unit)
  287                         return (ENXIO);
  288                 bcopy(&uartsio_synthinfo, synthinfo, sizeof(uartsio_synthinfo));
  289                 synthinfo->device = unit;
  290                 return (0);
  291                 break;
  292         case SNDCTL_MIDI_INFO:
  293                 midiinfo = (struct midi_info *)arg;
  294                 if (midiinfo->device != unit)
  295                         return (ENXIO);
  296                 bcopy(&uartsio_midiinfo, midiinfo, sizeof(uartsio_midiinfo));
  297                 midiinfo->device = unit;
  298                 return (0);
  299                 break;
  300         default:
  301                 return (ENOSYS);
  302         }
  303         /* NOTREACHED */
  304         return (EINVAL);
  305 }
  306 
  307 static void
  308 uartsio_intr(void *arg)
  309 {
  310         sc_p scp;
  311         mididev_info *devinfo;
  312 
  313         scp = (sc_p)arg;
  314         devinfo = scp->devinfo;
  315 
  316         mtx_lock(&devinfo->flagqueue_mtx);
  317         uartsio_xmit(scp);
  318         mtx_unlock(&devinfo->flagqueue_mtx);
  319 
  320         /* Invoke the upper layer. */
  321         midi_intr(devinfo);
  322 }
  323 
  324 static int
  325 uartsio_callback(void *di, int reason)
  326 {
  327         int unit;
  328         sc_p scp;
  329         mididev_info *d;
  330 
  331         d = (mididev_info *)di;
  332 
  333         mtx_assert(&d->flagqueue_mtx, MA_OWNED);
  334 
  335         if (d == NULL) {
  336                 MIDI_DEBUG(printf("uartsio_callback: device not configured.\n"));
  337                 return (ENXIO);
  338         }
  339 
  340         unit = d->unit;
  341         scp = d->softc;
  342 
  343         switch (reason & MIDI_CB_REASON_MASK) {
  344         case MIDI_CB_START:
  345                 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0)
  346                         /* Begin recording. */
  347                         d->flags |= MIDI_F_READING;
  348                 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
  349                         uartsio_startplay(scp);
  350                 break;
  351         case MIDI_CB_STOP:
  352         case MIDI_CB_ABORT:
  353                 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0)
  354                         /* Stop recording. */
  355                         d->flags &= ~MIDI_F_READING;
  356                 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0)
  357                         /* Stop Playing. */
  358                         d->flags &= ~MIDI_F_WRITING;
  359                 break;
  360         }
  361 
  362         return (0);
  363 }
  364 
  365 /*
  366  * The functions below here are the libraries for the above ones.
  367  */
  368 
  369 /*
  370  * Starts to play the data in the output queue.
  371  */
  372 static void
  373 uartsio_startplay(sc_p scp)
  374 {
  375         mididev_info *devinfo;
  376 
  377         devinfo = scp->devinfo;
  378 
  379         mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
  380 
  381         /* Can we play now? */
  382         if (devinfo->midi_dbuf_out.rl == 0)
  383                 return;
  384 
  385         devinfo->flags |= MIDI_F_WRITING;
  386         uartsio_xmit(scp);
  387 }
  388 
  389 static int
  390 uartsio_xmit(sc_p scp)
  391 {
  392         mididev_info *devinfo;
  393         midi_dbuf *dbuf;
  394         int lsr, msr, iir, i, txsize, leni, leno;
  395         u_char c[TX_FIFO_SIZE];
  396 
  397         devinfo = scp->devinfo;
  398 
  399         mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
  400 
  401         mtx_lock(&scp->mtx);
  402         for (;;) {
  403                 /* Read the received data. */
  404                 while (((lsr = uartsio_readport(scp, com_lsr)) & LSR_RCV_MASK) != 0) {
  405                         /* Is this a data or an error/break? */
  406                         if ((lsr & LSR_RXRDY) == 0)
  407                                 printf("uartsio_xmit: receive error or break in unit %d.\n", devinfo->unit);
  408                         else {
  409                                 /* Receive the data. */
  410                                 c[0] = uartsio_readport(scp, com_data);
  411                                 mtx_unlock(&scp->mtx);
  412                                 /* Queue into the passthru buffer and start transmitting if we can. */
  413                                 if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
  414                                         midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c[0], sizeof(c[0]), &leni);
  415                                         devinfo->flags |= MIDI_F_WRITING;
  416                                 }
  417                                 /* Queue if we are reading. Discard an active sensing. */
  418                                 if ((devinfo->flags & MIDI_F_READING) != 0 && c[0] != 0xfe)
  419                                         midibuf_input_intr(&devinfo->midi_dbuf_in, &c[0], sizeof(c[0]), &leni);
  420                                 mtx_lock(&scp->mtx);
  421                         }
  422                 }
  423                 mtx_unlock(&scp->mtx);
  424 
  425                 /* See which source to use. */
  426                 if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
  427                         dbuf = &devinfo->midi_dbuf_out;
  428                 else
  429                         dbuf = &devinfo->midi_dbuf_passthru;
  430 
  431                 /* Transmit the data in the queue. */
  432                 if ((devinfo->flags & MIDI_F_WRITING) != 0) {
  433                         /* Do we have the data to transmit? */
  434                         if (dbuf->rl == 0) {
  435                                 /* Stop playing. */
  436                                 devinfo->flags &= ~MIDI_F_WRITING;
  437                         } else {
  438                                 mtx_lock(&scp->mtx);
  439                                 /* Read LSR and MSR. */
  440                                 lsr = uartsio_readport(scp, com_lsr);
  441                                 msr = uartsio_readport(scp, com_msr);
  442                                 /* Is the device ready?. */
  443                                 if ((lsr & LSR_TXRDY) != 0 && (msr & MSR_CTS) != 0) {
  444                                         /* send the data. */
  445                                         txsize = scp->tx_size;
  446                                         if (dbuf->rl < txsize)
  447                                                 txsize = dbuf->rl;
  448                                         midibuf_output_intr(dbuf, c, txsize, &leno);
  449                                         for (i = 0 ; i < txsize ; i++)
  450                                                 uartsio_writeport(scp, com_data, c[i]);
  451                                         /* We are playing now. */
  452                                         devinfo->flags |= MIDI_F_WRITING;
  453                                 } else {
  454                                         /* Do we have the data to transmit? */
  455                                         if (dbuf->rl > 0)
  456                                         /* Wait for the next interrupt. */
  457                                                 devinfo->flags |= MIDI_F_WRITING;
  458                                 }
  459                                 mtx_unlock(&scp->mtx);
  460                         }
  461                 }
  462                 mtx_lock(&scp->mtx);
  463                 if (((iir = uartsio_readport(scp, com_iir)) & IIR_IMASK) == IIR_NOPEND)
  464                         break;
  465         }
  466         mtx_unlock(&scp->mtx);
  467 
  468         return (0);
  469 }
  470 
  471 /* Reads from a port. */
  472 static int
  473 uartsio_readport(sc_p scp, int off)
  474 {
  475         return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off);
  476 }
  477 
  478 /* Writes to a port. */
  479 static void
  480 uartsio_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 other than IO ports. */
  486 static int
  487 uartsio_allocres(sc_p scp, device_t dev)
  488 {
  489         if (scp->irq == NULL) {
  490                 scp->irq_rid = 0;
  491                 scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE);
  492         }
  493         if (scp->irq == NULL)
  494                 return (1);
  495 
  496         return (0);
  497 }
  498 
  499 /* Releases resources. */
  500 static void
  501 uartsio_releaseres(sc_p scp, device_t dev)
  502 {
  503         if (scp->irq != NULL) {
  504                 bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
  505                 scp->irq = NULL;
  506         }
  507         if (scp->io != NULL) {
  508                 bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io);
  509                 scp->io = NULL;
  510         }
  511 }
  512 
  513 static device_method_t uartsio_methods[] = {
  514 /* Device interface */
  515         DEVMETHOD(device_probe , uartsio_probe ),
  516         DEVMETHOD(device_attach, uartsio_attach),
  517 
  518         { 0, 0 },
  519 };
  520 
  521 static driver_t uartsio_driver = {
  522         "midi",
  523         uartsio_methods,
  524         sizeof(struct uartsio_softc),
  525 };
  526 
  527 DRIVER_MODULE(uartsio, isa, uartsio_driver, midi_devclass, 0, 0);

Cache object: 3460a80ed98047d5510846a8e0ab7c25


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