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/mpu.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  * The low level driver for Roland MPU-401 compatible Midi interfaces.
    3  * 
    4  * Copyright by Hannu Savolainen 1993
    5  * 
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions are
    8  * met: 1. Redistributions of source code must retain the above copyright
    9  * notice, this list of conditions and the following disclaimer. 2.
   10  * Redistributions in binary form must reproduce the above copyright notice,
   11  * this list of conditions and the following disclaimer in the documentation
   12  * and/or other materials provided with the distribution.
   13  * 
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
   15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   17  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  * 
   26  * Modified: Riccardo Facchetti  24 Mar 1995 - Added the Audio Excel DSP 16
   27  * initialization routine.
   28  *
   29  * Ported to the new Audio Driver by Luigi Rizzo:
   30  * (C) 1999 Seigo Tanimura
   31  *
   32  * This is the MPU401 midi interface driver for FreeBSD, based on the Luigi Sound Driver.
   33  * This handles io against /dev/midi, the midi {in, out}put event queues
   34  * and the event/message transmittion to/from an MPU401 interface.
   35  *
   36  * $FreeBSD: releng/5.0/sys/dev/sound/isa/mpu.c 93818 2002-04-04 21:03:38Z jhb $
   37  *
   38  */
   39 
   40 #include <dev/sound/midi/midi.h>
   41 #include <dev/sound/chip.h>
   42 #include <machine/cpufunc.h>
   43 
   44 #include <isa/isavar.h>
   45 #include <dev/sio/sioreg.h>
   46 #include <dev/ic/ns16550.h>
   47 
   48 static devclass_t midi_devclass;
   49 
   50 #ifndef DDB
   51 #undef DDB
   52 #define DDB(x)
   53 #endif /* DDB */
   54 
   55 #define MPU_DATAPORT   0
   56 #define MPU_CMDPORT    1
   57 #define MPU_STATPORT   1
   58 
   59 #define MPU_RESET      0xff
   60 #define MPU_UART       0x3f
   61 #define MPU_ACK        0xfe
   62 
   63 #define MPU_STATMASK   0xc0
   64 #define MPU_OUTPUTBUSY 0x40
   65 #define MPU_INPUTBUSY  0x80
   66 
   67 #define MPU_TRYDATA 50
   68 #define MPU_DELAY   25000
   69 
   70 /* Device flag.  */
   71 #define MPU_DF_NO_IRQ   1
   72 
   73 extern synthdev_info midisynth_op_desc;
   74 
   75 /* PnP IDs */
   76 static struct isa_pnp_id mpu_ids[] = {
   77         {0x01200001, "@H@2001 Midi Interface"}, /* @H@2001 */
   78         {0x01100001, "@H@1001 Midi Interface"}, /* @H@1001 */
   79 #if notdef
   80         /* TODO: write bridge driver for these devices */
   81         {0x0000630e, "CSC0000 Midi Interface"}, /* CSC0000 */
   82         {0x2100a865, "YMH0021 Midi Interface"}, /* YMH0021 */
   83         {0x80719304, "ADS7180 Midi Interface"}, /* ADS7180 */
   84         {0x0300561e, "GRV0003 Midi Interface"}, /* GRV0003 */
   85 #endif
   86 };
   87 
   88 /* These are the synthesizer and the midi interface information. */
   89 static struct synth_info mpu_synthinfo = {
   90         "MPU401 MIDI",
   91         0,
   92         SYNTH_TYPE_MIDI,
   93         0,
   94         0,
   95         128,
   96         128,
   97         128,
   98         SYNTH_CAP_INPUT,
   99 };
  100 
  101 static struct midi_info mpu_midiinfo = {
  102         "MPU401 MIDI",
  103         0,
  104         0,
  105         0,
  106 };
  107 
  108 /*
  109  * These functions goes into mpu_op_desc to get called
  110  * from sound.c.
  111  */
  112 
  113 static int mpu_probe(device_t dev);
  114 static int mpu_probe1(device_t dev);
  115 static int mpu_probe2(device_t dev);
  116 static int mpu_attach(device_t dev);
  117 static int mpusbc_probe(device_t dev);
  118 static int mpusbc_attach(device_t dev);
  119 
  120 static d_ioctl_t mpu_ioctl;
  121 static driver_intr_t mpu_intr;
  122 static midi_callback_t mpu_callback;
  123 
  124 /* Here is the parameter structure per a device. */
  125 struct mpu_softc {
  126         device_t dev; /* device information */
  127         mididev_info *devinfo; /* midi device information */
  128 
  129         struct mtx mtx; /* Mutex to protect the device. */
  130 
  131         struct resource *io; /* Base of io port */
  132         int io_rid; /* Io resource ID */
  133         u_long irq_val; /* Irq value */
  134         struct resource *irq; /* Irq */
  135         int irq_rid; /* Irq resource ID */
  136         void *ih; /* Interrupt cookie */
  137 
  138         int fflags; /* File flags */
  139 };
  140 
  141 typedef struct mpu_softc *sc_p;
  142 
  143 /* These functions are local. */
  144 static void mpu_startplay(sc_p scp);
  145 static void mpu_xmit(sc_p scp);
  146 static int mpu_resetmode(sc_p scp);
  147 static int mpu_uartmode(sc_p scp);
  148 static int mpu_waitack(sc_p scp);
  149 static int mpu_status(sc_p scp);
  150 static int mpu_command(sc_p scp, u_int8_t value);
  151 static int mpu_readdata(sc_p scp, u_int8_t *value);
  152 static int mpu_writedata(sc_p scp, u_int8_t value);
  153 static u_int mpu_readport(sc_p scp, int off);
  154 static void mpu_writeport(sc_p scp, int off, u_int8_t value);
  155 static int mpu_allocres(sc_p scp, device_t dev);
  156 static void mpu_releaseres(sc_p scp, device_t dev);
  157 
  158 /*
  159  * This is the device descriptor for the midi device.
  160  */
  161 static mididev_info mpu_op_desc = {
  162         "MPU401 midi",
  163 
  164         SNDCARD_MPU401,
  165 
  166         NULL,
  167         NULL,
  168         mpu_ioctl,
  169 
  170         mpu_callback,
  171 
  172         MIDI_BUFFSIZE, /* Queue Length */
  173 
  174         0, /* XXX This is not an *audio* device! */
  175 };
  176 
  177 /*
  178  * Here are the main functions to interact to the user process.
  179  */
  180 
  181 static int
  182 mpu_probe(device_t dev)
  183 {
  184         sc_p scp;
  185         int ret;
  186 
  187         /* Check isapnp ids */
  188         if (isa_get_logicalid(dev) != 0)
  189                 return (ISA_PNP_PROBE(device_get_parent(dev), dev, mpu_ids));
  190 
  191         scp = device_get_softc(dev);
  192 
  193         device_set_desc(dev, mpu_op_desc.name);
  194         bzero(scp, sizeof(*scp));
  195 
  196         scp->io_rid = 0;
  197         ret = mpu_probe1(dev);
  198         if (ret != 0)
  199                 return (ret);
  200         ret = mpu_probe2(dev);
  201         if (ret != 0)
  202                 return (ret);
  203 
  204         return (0);
  205 }
  206 
  207 /*
  208  * Make sure this is an MPU401, not an 16550 uart.
  209  * Called only for non-pnp devices.
  210  */
  211 static int
  212 mpu_probe1(device_t dev)
  213 {
  214         sc_p scp;
  215         int iir;
  216         struct resource *io;
  217 
  218         scp = device_get_softc(dev);
  219 
  220         /*
  221          * If an MPU401 is ready to both input and output,
  222          * the status register value is zero, which may
  223          * confuse an 16550 uart to probe as an MPU401.
  224          * We read the IIR (base + 2), which is not used
  225          * by an MPU401.
  226          */
  227         io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 3, RF_ACTIVE);
  228         iir = bus_space_read_1(rman_get_bustag(io), rman_get_bushandle(io), com_iir) & 0xff;
  229         bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, io);
  230         if ((iir & ~(IIR_IMASK | IIR_FIFO_MASK)) == 0)
  231                 /* Likely to be an 16550. */
  232                 return (ENXIO);
  233 
  234         return (0);
  235 }
  236 
  237 /* Look up the irq. */
  238 static int
  239 mpu_probe2(device_t dev)
  240 {
  241         sc_p scp;
  242         int unit, i;
  243         intrmask_t irqp0, irqp1;
  244 
  245         scp = device_get_softc(dev);
  246         unit = device_get_unit(dev);
  247 
  248         scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 2, RF_ACTIVE);
  249         if (scp->io == NULL)
  250                 return (ENXIO);
  251 
  252         MIDI_DEBUG(printf("mpu%d: probing.\n", unit));
  253 
  254         /* Reset the interface. */
  255         if (mpu_resetmode(scp) != 0 || mpu_waitack(scp) != 0) {
  256                 printf("mpu%d: reset failed.\n", unit);
  257                 mpu_releaseres(scp, dev);
  258                 return (ENXIO);
  259         }
  260 
  261         /*
  262          * At this point, we are likely to have an interface.
  263          *
  264          * Switching the interface to uart mode gives us an interrupt.
  265          * We can make use of it to determine the irq.
  266          * Idea-stolen-from: sys/isa/sio.c:sioprobe()
  267          */
  268 
  269         critical_enter();
  270 
  271         /*
  272          * See the initial irq. We have to do this now,
  273          * otherwise a midi module/instrument might send
  274          * an active sensing, to mess up the irq.
  275          */
  276         irqp0 = isa_irq_pending();
  277         irqp1 = 0;
  278 
  279         /* Switch to uart mode. */
  280         if (mpu_uartmode(scp) != 0) {
  281                 critical_exit();
  282                 printf("mpu%d: mode switching failed.\n", unit);
  283                 mpu_releaseres(scp, dev);
  284                 return (ENXIO);
  285         }
  286 
  287         if (device_get_flags(dev) & MPU_DF_NO_IRQ) {
  288                 irqp0 = irqp1 = 0;
  289                 goto no_irq;
  290         }
  291 
  292         /* See which irq we have now. */
  293         for (i = 0 ; i < MPU_TRYDATA ; i++) {
  294                 DELAY(MPU_DELAY);
  295                 irqp1 = isa_irq_pending();
  296                 if (irqp1 != irqp0)
  297                         break;
  298         }
  299         if (irqp1 == irqp0) {
  300                 critical_exit();
  301                 printf("mpu%d: switching the mode gave no interrupt.\n", unit);
  302                 mpu_releaseres(scp, dev);
  303                 return (ENXIO);
  304         }
  305 
  306 no_irq:
  307         /* Wait to see an ACK. */
  308         if (mpu_waitack(scp) != 0) {
  309                 critical_exit();
  310                 printf("mpu%d: not acked.\n", unit);
  311                 mpu_releaseres(scp, dev);
  312                 return (ENXIO);
  313         }
  314 
  315         critical_exit();
  316 
  317         if (device_get_flags(dev) & MPU_DF_NO_IRQ)
  318                 scp->irq_val = 0;
  319         else
  320                 /* We have found the irq. */
  321                 scp->irq_val = ffs(~irqp0 & irqp1) - 1;
  322 
  323         MIDI_DEBUG(printf("mpu%d: probed.\n", unit));
  324 
  325         return (0);
  326 }
  327 
  328 static int
  329 mpusbc_probe(device_t dev)
  330 {
  331         char *s;
  332         sc_p scp;
  333         struct sndcard_func *func;
  334 
  335         /* The parent device has already been probed. */
  336 
  337         func = device_get_ivars(dev);
  338         if (func == NULL || func->func != SCF_MIDI)
  339                 return (ENXIO);
  340 
  341         s = "SB Midi Interface";
  342 
  343         scp = device_get_softc(dev);
  344         bzero(scp, sizeof(*scp));
  345         scp->io_rid = 1;
  346         scp->irq_rid = 0;
  347         device_set_desc(dev, s);
  348         return (0);
  349 }
  350 
  351 static int
  352 mpu_attach(device_t dev)
  353 {
  354         sc_p scp;
  355         mididev_info *devinfo;
  356 
  357         scp = device_get_softc(dev);
  358 
  359         MIDI_DEBUG(printf("mpu: attaching.\n"));
  360 
  361         mtx_init(&scp->mtx, "mpumid", NULL, MTX_DEF);
  362 
  363         /* Allocate the resources, switch to uart mode. */
  364         if (mpu_allocres(scp, dev) || mpu_uartmode(scp)) {
  365                 mpu_releaseres(scp, dev);
  366                 return (ENXIO);
  367         }
  368 
  369         /* mpu_probe() has put the interface to uart mode. */
  370 
  371         /* Fill the softc. */
  372         scp->dev = dev;
  373         scp->devinfo = devinfo = create_mididev_info_unit(MDT_MIDI, &mpu_op_desc, &midisynth_op_desc);
  374 
  375         /* Fill the midi info. */
  376         if (scp->irq != NULL)
  377                 snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x irq %d",
  378                          (u_int)rman_get_start(scp->io), (int)rman_get_start(scp->irq));
  379         else
  380                 snprintf(devinfo->midistat, sizeof(devinfo->midistat), "at 0x%x",
  381                          (u_int)rman_get_start(scp->io));
  382 
  383         midiinit(devinfo, dev);
  384 
  385         /* Now we can handle the interrupts. */
  386         if (scp->irq != NULL)
  387                 bus_setup_intr(dev, scp->irq, INTR_TYPE_AV, mpu_intr, scp,
  388                                &scp->ih);
  389 
  390         MIDI_DEBUG(printf("mpu: attached.\n"));
  391 
  392         return (0);
  393 }
  394 
  395 static int
  396 mpusbc_attach(device_t dev)
  397 {
  398         sc_p scp;
  399         int unit;
  400 
  401         scp = device_get_softc(dev);
  402         unit = device_get_unit(dev);
  403 
  404         mpu_attach(dev);
  405 
  406         return (0);
  407 }
  408 
  409 static int
  410 mpu_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  411 {
  412         sc_p scp;
  413         mididev_info *devinfo;
  414         int unit;
  415         struct synth_info *synthinfo;
  416         struct midi_info *midiinfo;
  417 
  418         unit = MIDIUNIT(i_dev);
  419 
  420         MIDI_DEBUG(printf("mpu_ioctl: unit %d, cmd %s.\n", unit, midi_cmdname(cmd, cmdtab_midiioctl)));
  421 
  422         devinfo = get_mididev_info(i_dev, &unit);
  423         if (devinfo == NULL) {
  424                 MIDI_DEBUG(printf("mpu_ioctl: unit %d is not configured.\n", unit));
  425                 return (ENXIO);
  426         }
  427         scp = devinfo->softc;
  428 
  429         switch (cmd) {
  430         case SNDCTL_SYNTH_INFO:
  431                 synthinfo = (struct synth_info *)arg;
  432                 if (synthinfo->device != unit)
  433                         return (ENXIO);
  434                 bcopy(&mpu_synthinfo, synthinfo, sizeof(mpu_synthinfo));
  435                 synthinfo->device = unit;
  436                 return (0);
  437                 break;
  438         case SNDCTL_MIDI_INFO:
  439                 midiinfo = (struct midi_info *)arg;
  440                 if (midiinfo->device != unit)
  441                         return (ENXIO);
  442                 bcopy(&mpu_midiinfo, midiinfo, sizeof(mpu_midiinfo));
  443                 midiinfo->device = unit;
  444                 return (0);
  445                 break;
  446         default:
  447                 return (ENOSYS);
  448         }
  449         /* NOTREACHED */
  450         return (EINVAL);
  451 }
  452 
  453 static void
  454 mpu_intr(void *arg)
  455 {
  456         sc_p scp;
  457         u_char c;
  458         mididev_info *devinfo;
  459         int leni;
  460 
  461         scp = (sc_p)arg;
  462         devinfo = scp->devinfo;
  463 
  464         mtx_lock(&devinfo->flagqueue_mtx);
  465         mtx_lock(&scp->mtx);
  466 
  467         /* Read the received data. */
  468         while ((mpu_status(scp) & MPU_INPUTBUSY) == 0) {
  469                 /* Receive the data. */
  470                 mpu_readdata(scp, &c);
  471                 mtx_unlock(&scp->mtx);
  472                 /* Queue into the passthru buffer and start transmitting if we can. */
  473                 if ((devinfo->flags & MIDI_F_PASSTHRU) != 0 && ((devinfo->flags & MIDI_F_BUSY) == 0 || (devinfo->fflags & FWRITE) == 0)) {
  474                         midibuf_input_intr(&devinfo->midi_dbuf_passthru, &c, sizeof(c), &leni);
  475                         devinfo->callback(devinfo, MIDI_CB_START | MIDI_CB_WR);
  476                 }
  477                 /* Queue if we are reading. Discard an active sensing. */
  478                 if ((devinfo->flags & MIDI_F_READING) != 0 && c != 0xfe) {
  479                         midibuf_input_intr(&devinfo->midi_dbuf_in, &c, sizeof(c), &leni);
  480                 }
  481                 mtx_lock(&scp->mtx);
  482         }
  483         mtx_unlock(&scp->mtx);
  484         mtx_unlock(&devinfo->flagqueue_mtx);
  485 
  486         /* Invoke the upper layer. */
  487         midi_intr(devinfo);
  488 }
  489 
  490 static int
  491 mpu_callback(void *di, int reason)
  492 {
  493         int unit;
  494         sc_p scp;
  495         mididev_info *d;
  496 
  497         d = (mididev_info *)di;
  498 
  499         mtx_assert(&d->flagqueue_mtx, MA_OWNED);
  500 
  501         if (d == NULL) {
  502                 MIDI_DEBUG(printf("mpu_callback: device not configured.\n"));
  503                 return (ENXIO);
  504         }
  505 
  506         unit = d->unit;
  507         scp = d->softc;
  508 
  509         switch (reason & MIDI_CB_REASON_MASK) {
  510         case MIDI_CB_START:
  511                 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) == 0)
  512                         /* Begin recording. */
  513                         d->flags |= MIDI_F_READING;
  514                 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) == 0)
  515                         /* Start playing. */
  516                         mpu_startplay(scp);
  517                 break;
  518         case MIDI_CB_STOP:
  519         case MIDI_CB_ABORT:
  520                 if ((reason & MIDI_CB_RD) != 0 && (d->flags & MIDI_F_READING) != 0)
  521                         /* Stop recording. */
  522                         d->flags &= ~MIDI_F_READING;
  523                 if ((reason & MIDI_CB_WR) != 0 && (d->flags & MIDI_F_WRITING) != 0)
  524                         /* Stop Playing. */
  525                         d->flags &= ~MIDI_F_WRITING;
  526                 break;
  527         }
  528 
  529         return (0);
  530 }
  531 
  532 /*
  533  * The functions below here are the libraries for the above ones.
  534  */
  535 
  536 /*
  537  * Starts to play the data in the output queue.
  538  */
  539 static void
  540 mpu_startplay(sc_p scp)
  541 {
  542         mididev_info *devinfo;
  543 
  544         devinfo = scp->devinfo;
  545 
  546         mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
  547 
  548         /* Can we play now? */
  549         if (devinfo->midi_dbuf_out.rl == 0)
  550                 return;
  551 
  552         devinfo->flags |= MIDI_F_WRITING;
  553         mpu_xmit(scp);
  554 }
  555 
  556 static void
  557 mpu_xmit(sc_p scp)
  558 {
  559         register mididev_info *devinfo;
  560         register midi_dbuf *dbuf;
  561         u_char c;
  562         int leno;
  563 
  564         devinfo = scp->devinfo;
  565 
  566         mtx_assert(&devinfo->flagqueue_mtx, MA_OWNED);
  567 
  568         /* See which source to use. */
  569         if ((devinfo->flags & MIDI_F_PASSTHRU) == 0 || ((devinfo->flags & MIDI_F_BUSY) != 0 && (devinfo->fflags & FWRITE) != 0))
  570                 dbuf = &devinfo->midi_dbuf_out;
  571         else
  572                 dbuf = &devinfo->midi_dbuf_passthru;
  573 
  574         /* Transmit the data in the queue. */
  575         while ((devinfo->flags & MIDI_F_WRITING) != 0) {
  576                 if (dbuf->rl == 0) 
  577                         break;
  578                 else {
  579                         mtx_lock(&scp->mtx);
  580                         /* XXX Wait until we can write the data. */
  581                         if ((mpu_status(scp) & MPU_OUTPUTBUSY) == 0) {
  582                                 /* Send the data. */
  583                                 midibuf_output_intr(dbuf, &c, sizeof(c), &leno);
  584                                 mpu_writedata(scp, c);
  585                                 /* We are playing now. */
  586                                 devinfo->flags |= MIDI_F_WRITING;
  587                         }
  588                         mtx_unlock(&scp->mtx);
  589                 }
  590         }
  591         /* Stop playing. */
  592         devinfo->flags &= ~MIDI_F_WRITING;
  593 }
  594 
  595 
  596 /* 
  597  * Reset mpu.
  598  * The caller must lock scp->mtx before calling this function if needed.
  599  */
  600 static int
  601 mpu_resetmode(sc_p scp)
  602 {
  603         int i, resp;
  604 
  605         /* Reset the mpu. */
  606         resp = 0;
  607         for (i = 0 ; i < MPU_TRYDATA ; i++) {
  608                 resp = mpu_command(scp, MPU_RESET);
  609                 if (resp == 0)
  610                         break;
  611         }
  612         if (resp != 0)
  613                 return (1);
  614 
  615         DELAY(MPU_DELAY);
  616         return (0);
  617 }
  618 
  619 /*
  620  * Switch to uart mode.
  621  * The caller must lock scp->mtx before calling this function if needed.
  622  */
  623 static int
  624 mpu_uartmode(sc_p scp)
  625 {
  626         int i, resp;
  627 
  628         /* Switch to uart mode. */
  629         resp = 0;
  630         for (i = 0 ; i < MPU_TRYDATA ; i++) {
  631                 resp = mpu_command(scp, MPU_UART);
  632                 if (resp == 0)
  633                         break;
  634         }
  635         if (resp != 0)
  636                 return (1);
  637 
  638         DELAY(MPU_DELAY);
  639         return (0);
  640 }
  641 
  642 /*
  643  * Wait to see an ACK.
  644  * The caller must lock scp->mtx before calling this function if needed.
  645  */
  646 static int
  647 mpu_waitack(sc_p scp)
  648 {
  649         int i;
  650         u_int8_t resp;
  651 
  652         resp = 0;
  653         for (i = 0 ; i < MPU_TRYDATA ; i++) {
  654                 if (mpu_readdata(scp, &resp) == 0)
  655                         break;
  656         }
  657         if (resp != MPU_ACK)
  658                 return (1);
  659 
  660         DELAY(MPU_DELAY);
  661         return (0);
  662 }
  663 
  664 /* Reads the status. */
  665 static int
  666 mpu_status(sc_p scp)
  667 {
  668         return mpu_readport(scp, MPU_STATPORT);
  669 }
  670 
  671 /* Writes a command. */
  672 static int
  673 mpu_command(sc_p scp, u_int8_t value)
  674 {
  675         u_int status;
  676 
  677         /* Is the interface ready to write? */
  678         status = mpu_status(scp);
  679         if ((status & MPU_OUTPUTBUSY) != 0)
  680                 /* The interface is busy. */
  681                 return (EAGAIN);
  682 
  683         mpu_writeport(scp, MPU_CMDPORT, value);
  684 
  685         return (0);
  686 }
  687 
  688 /* Reads a byte of data. */
  689 static int
  690 mpu_readdata(sc_p scp, u_int8_t *value)
  691 {
  692         u_int status;
  693 
  694         if (value == NULL)
  695                 return (EINVAL);
  696 
  697         /* Is the interface ready to write? */
  698         status = mpu_status(scp);
  699         if ((status & MPU_INPUTBUSY) != 0)
  700                 /* The interface is busy. */
  701                 return (EAGAIN);
  702 
  703         *value = (u_int8_t)(mpu_readport(scp, MPU_DATAPORT) & 0xff);
  704 
  705         return (0);
  706 }
  707 
  708 /* Writes a byte of data. */
  709 static int
  710 mpu_writedata(sc_p scp, u_int8_t value)
  711 {
  712         u_int status;
  713 
  714         /* Is the interface ready to write? */
  715         status = mpu_status(scp);
  716         if ((status & MPU_OUTPUTBUSY) != 0)
  717                 /* The interface is busy. */
  718                 return (EAGAIN);
  719 
  720         mpu_writeport(scp, MPU_DATAPORT, value);
  721 
  722         return (0);
  723 }
  724 
  725 /* Reads from a port. */
  726 static u_int
  727 mpu_readport(sc_p scp, int off)
  728 {
  729         return bus_space_read_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off) & 0xff;
  730 }
  731 
  732 /* Writes to a port. */
  733 static void
  734 mpu_writeport(sc_p scp, int off, u_int8_t value)
  735 {
  736         bus_space_write_1(rman_get_bustag(scp->io), rman_get_bushandle(scp->io), off, value);
  737 }
  738 
  739 /* Allocates resources. */
  740 static int
  741 mpu_allocres(sc_p scp, device_t dev)
  742 {
  743         if (scp->io == NULL) {
  744                 scp->io = bus_alloc_resource(dev, SYS_RES_IOPORT, &scp->io_rid, 0, ~0, 2, RF_ACTIVE);
  745                 if (scp->io == NULL)
  746                         return (1);
  747         }
  748         if (scp->irq == NULL && !(device_get_flags(dev) & MPU_DF_NO_IRQ)) {
  749                 if (scp->irq_val == 0)
  750                         scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
  751                 else
  752                         scp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &scp->irq_rid, scp->irq_val, scp->irq_val, 1, RF_ACTIVE | RF_SHAREABLE);
  753                 if (scp->irq == NULL)
  754                         return (1);
  755         }
  756 
  757         return (0);
  758 }
  759 
  760 /* Releases resources. */
  761 static void
  762 mpu_releaseres(sc_p scp, device_t dev)
  763 {
  764         if (scp->irq != NULL) {
  765                 bus_release_resource(dev, SYS_RES_IRQ, scp->irq_rid, scp->irq);
  766                 scp->irq = NULL;
  767         }
  768         if (scp->io != NULL) {
  769                 bus_release_resource(dev, SYS_RES_IOPORT, scp->io_rid, scp->io);
  770                 scp->io = NULL;
  771         }
  772         mtx_destroy(&scp->mtx);
  773 }
  774 
  775 static device_method_t mpu_methods[] = {
  776         /* Device interface */
  777         DEVMETHOD(device_probe , mpu_probe ),
  778         DEVMETHOD(device_attach, mpu_attach),
  779 
  780         { 0, 0 },
  781 };
  782 
  783 static driver_t mpu_driver = {
  784         "midi",
  785         mpu_methods,
  786         sizeof(struct mpu_softc),
  787 };
  788 
  789 DRIVER_MODULE(mpu, isa, mpu_driver, midi_devclass, 0, 0);
  790 
  791 static device_method_t mpusbc_methods[] = {
  792         /* Device interface */
  793         DEVMETHOD(device_probe , mpusbc_probe ),
  794         DEVMETHOD(device_attach, mpusbc_attach),
  795 
  796         { 0, 0 },
  797 };
  798 
  799 static driver_t mpusbc_driver = {
  800         "midi",
  801         mpusbc_methods,
  802         sizeof(struct mpu_softc),
  803 };
  804 
  805 DRIVER_MODULE(mpusbc, sbc, mpusbc_driver, midi_devclass, 0, 0);

Cache object: ddf6f6581ca78f94a9bc1c2bbe13eb94


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