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/macio/davbus.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 2008 by Marco Trillo. All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * $FreeBSD$
   28  */
   29 
   30 /*
   31  *      Apple DAVbus audio controller.
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/malloc.h>
   40 #include <sys/module.h>
   41 #include <sys/mutex.h>
   42 #include <sys/rman.h>
   43 
   44 #include <dev/ofw/ofw_bus.h>
   45 
   46 #ifdef HAVE_KERNEL_OPTION_HEADERS
   47 #include "opt_snd.h"
   48 #endif
   49 
   50 #include <dev/sound/pcm/sound.h>
   51 
   52 #include <dev/sound/macio/aoa.h>
   53 #include <dev/sound/macio/davbusreg.h>
   54 
   55 #include <machine/intr_machdep.h>
   56 #include <machine/resource.h>
   57 #include <machine/bus.h>
   58 
   59 #include "mixer_if.h"
   60 
   61 struct davbus_softc {
   62         struct aoa_softc         aoa;
   63         phandle_t                node;
   64         phandle_t                soundnode;
   65         struct resource         *reg;
   66         struct mtx               mutex;
   67         int                      device_id;
   68         u_int                    output_mask;
   69         u_int                   (*read_status)(struct davbus_softc *, u_int);
   70         void                    (*set_outputs)(struct davbus_softc *, u_int);
   71 };
   72 
   73 static int      davbus_probe(device_t);
   74 static int      davbus_attach(device_t);
   75 static void     davbus_cint(void *);
   76 
   77 static device_method_t pcm_davbus_methods[] = {
   78         /* Device interface. */
   79         DEVMETHOD(device_probe,         davbus_probe),
   80         DEVMETHOD(device_attach,        davbus_attach),
   81         { 0, 0 }
   82 };
   83 
   84 static driver_t pcm_davbus_driver = {
   85         "pcm",
   86         pcm_davbus_methods,
   87         PCM_SOFTC_SIZE
   88 };
   89 
   90 DRIVER_MODULE(pcm_davbus, macio, pcm_davbus_driver, 0, 0);
   91 MODULE_DEPEND(pcm_davbus, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
   92 
   93 /*****************************************************************************
   94                         Probe and attachment routines.
   95  *****************************************************************************/
   96 static int
   97 davbus_probe(device_t self)
   98 {
   99         const char              *name;
  100 
  101         name = ofw_bus_get_name(self);
  102         if (!name)
  103                 return (ENXIO);
  104 
  105         if (strcmp(name, "davbus") != 0)
  106                 return (ENXIO);
  107 
  108         device_set_desc(self, "Apple DAVBus Audio Controller");
  109 
  110         return (0);
  111 }
  112 
  113 /*
  114  * Burgundy codec control
  115  */
  116 
  117 static int      burgundy_init(struct snd_mixer *m);
  118 static int      burgundy_uninit(struct snd_mixer *m);
  119 static int      burgundy_reinit(struct snd_mixer *m);
  120 static void     burgundy_write_locked(struct davbus_softc *, u_int, u_int);
  121 static void     burgundy_set_outputs(struct davbus_softc *d, u_int mask);
  122 static u_int    burgundy_read_status(struct davbus_softc *d, u_int status);
  123 static int      burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left,
  124                     unsigned right);
  125 static u_int32_t        burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src);
  126 
  127 static kobj_method_t burgundy_mixer_methods[] = {
  128         KOBJMETHOD(mixer_init,          burgundy_init),
  129         KOBJMETHOD(mixer_uninit,        burgundy_uninit),
  130         KOBJMETHOD(mixer_reinit,        burgundy_reinit),
  131         KOBJMETHOD(mixer_set,           burgundy_set),
  132         KOBJMETHOD(mixer_setrecsrc,     burgundy_setrecsrc),
  133         KOBJMETHOD_END
  134 };
  135 
  136 MIXER_DECLARE(burgundy_mixer);
  137 
  138 static int
  139 burgundy_init(struct snd_mixer *m)
  140 {
  141         struct davbus_softc *d;
  142 
  143         d = mix_getdevinfo(m);
  144 
  145         d->read_status = burgundy_read_status;
  146         d->set_outputs = burgundy_set_outputs;
  147 
  148         /*
  149          * We configure the Burgundy codec as follows:
  150          *
  151          *      o Input subframe 0 is connected to input digital
  152          *        stream A (ISA).
  153          *      o Stream A (ISA) is mixed in mixer 2 (MIX2).
  154          *      o Output of mixer 2 (MIX2) is routed to output sources
  155          *        OS0 and OS1 which can be converted to analog.
  156          *
  157          */
  158         mtx_lock(&d->mutex);
  159 
  160         burgundy_write_locked(d, 0x16700, 0x40);
  161 
  162         burgundy_write_locked(d, BURGUNDY_MIX0_REG, 0); 
  163         burgundy_write_locked(d, BURGUNDY_MIX1_REG, 0);
  164         burgundy_write_locked(d, BURGUNDY_MIX2_REG, BURGUNDY_MIX_ISA);
  165         burgundy_write_locked(d, BURGUNDY_MIX3_REG, 0);
  166 
  167         burgundy_write_locked(d, BURGUNDY_OS_REG, BURGUNDY_OS0_MIX2 | 
  168             BURGUNDY_OS1_MIX2);
  169 
  170         burgundy_write_locked(d, BURGUNDY_SDIN_REG, BURGUNDY_ISA_SF0);
  171 
  172         /* Set several digital scalers to unity gain. */
  173         burgundy_write_locked(d, BURGUNDY_MXS2L_REG, BURGUNDY_MXS_UNITY);
  174         burgundy_write_locked(d, BURGUNDY_MXS2R_REG, BURGUNDY_MXS_UNITY);
  175         burgundy_write_locked(d, BURGUNDY_OSS0L_REG, BURGUNDY_OSS_UNITY);
  176         burgundy_write_locked(d, BURGUNDY_OSS0R_REG, BURGUNDY_OSS_UNITY);
  177         burgundy_write_locked(d, BURGUNDY_OSS1L_REG, BURGUNDY_OSS_UNITY);
  178         burgundy_write_locked(d, BURGUNDY_OSS1R_REG, BURGUNDY_OSS_UNITY);
  179         burgundy_write_locked(d, BURGUNDY_ISSAL_REG, BURGUNDY_ISS_UNITY);
  180         burgundy_write_locked(d, BURGUNDY_ISSAR_REG, BURGUNDY_ISS_UNITY);
  181 
  182         burgundy_set_outputs(d, burgundy_read_status(d, 
  183             bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
  184 
  185         mtx_unlock(&d->mutex);
  186 
  187         mix_setdevs(m, SOUND_MASK_VOLUME);
  188 
  189         return (0);
  190 }
  191 
  192 static int
  193 burgundy_uninit(struct snd_mixer *m)
  194 {
  195         return (0);
  196 }
  197 
  198 static int
  199 burgundy_reinit(struct snd_mixer *m)
  200 {
  201         return (0);
  202 }
  203 
  204 static void
  205 burgundy_write_locked(struct davbus_softc *d, u_int reg, u_int val)
  206 {
  207         u_int size, addr, offset, data, i;
  208 
  209         size = (reg & 0x00FF0000) >> 16;
  210         addr = (reg & 0x0000FF00) >> 8;
  211         offset = reg & 0xFF;
  212 
  213         for (i = offset; i < offset + size; ++i) {
  214                 data = BURGUNDY_CTRL_WRITE | (addr << 12) | 
  215                     ((size + offset - 1) << 10) | (i << 8) | (val & 0xFF);
  216                 if (i == offset)
  217                         data |= BURGUNDY_CTRL_RESET;
  218 
  219                 bus_write_4(d->reg, DAVBUS_CODEC_CTRL, data);
  220 
  221                 while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) &
  222                     DAVBUS_CODEC_BUSY)
  223                         DELAY(1);
  224                 
  225                 val >>= 8; /* next byte. */
  226         }       
  227 }
  228 
  229 /* Must be called with d->mutex held. */
  230 static void
  231 burgundy_set_outputs(struct davbus_softc *d, u_int mask)
  232 {
  233         u_int   x = 0;
  234 
  235         if (mask == d->output_mask)
  236                 return;
  237 
  238         /*
  239          *      Bordeaux card wirings:
  240          *              Port 15:        RCA out
  241          *              Port 16:        Minijack out
  242          *              Port 17:        Internal speaker
  243          *
  244          *      B&W G3 wirings:
  245          *              Port 14:        Minijack out
  246          *              Port 17:        Internal speaker
  247          */
  248 
  249         DPRINTF(("Enabled outputs:"));
  250         if (mask & (1 << 0)) {
  251                 DPRINTF((" SPEAKER"));
  252                 x |= BURGUNDY_P17M_EN;
  253         }
  254         if (mask & (1 << 1)) {
  255                 DPRINTF((" HEADPHONES"));
  256                 x |= BURGUNDY_P14L_EN | BURGUNDY_P14R_EN;       
  257         }
  258         DPRINTF(("\n"));
  259 
  260         burgundy_write_locked(d, BURGUNDY_MUTE_REG, x);
  261         d->output_mask = mask;
  262 }
  263 
  264 static u_int
  265 burgundy_read_status(struct davbus_softc *d, u_int status)
  266 {
  267         if (status & 0x4)
  268                 return (1 << 1);
  269         else
  270                 return (1 << 0);
  271 }
  272 
  273 static int
  274 burgundy_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  275 {
  276         struct davbus_softc *d;
  277         int lval, rval;
  278 
  279         lval = ((100 - left) * 15 / 100) & 0xf;
  280         rval = ((100 - right) * 15 / 100) & 0xf;
  281         DPRINTF(("volume %d %d\n", lval, rval));
  282 
  283         d = mix_getdevinfo(m);
  284 
  285         switch (dev) {
  286         case SOUND_MIXER_VOLUME:
  287                 mtx_lock(&d->mutex);
  288 
  289                 burgundy_write_locked(d, BURGUNDY_OL13_REG, lval);
  290                 burgundy_write_locked(d, BURGUNDY_OL14_REG, (rval << 4) | lval);
  291                 burgundy_write_locked(d, BURGUNDY_OL15_REG, (rval << 4) | lval);
  292                 burgundy_write_locked(d, BURGUNDY_OL16_REG, (rval << 4) | lval);
  293                 burgundy_write_locked(d, BURGUNDY_OL17_REG, lval);
  294 
  295                 mtx_unlock(&d->mutex);
  296 
  297                 return (left | (right << 8));
  298         }
  299 
  300         return (0);
  301 }
  302 
  303 static u_int32_t
  304 burgundy_setrecsrc(struct snd_mixer *m, u_int32_t src)
  305 {
  306         return (0);
  307 }
  308 
  309 /*
  310  * Screamer Codec Control
  311  */
  312 
  313 static int      screamer_init(struct snd_mixer *m);
  314 static int      screamer_uninit(struct snd_mixer *m);
  315 static int      screamer_reinit(struct snd_mixer *m);
  316 static void     screamer_write_locked(struct davbus_softc *, u_int, u_int);
  317 static void     screamer_set_outputs(struct davbus_softc *d, u_int mask);
  318 static u_int    screamer_read_status(struct davbus_softc *d, u_int status);
  319 static int      screamer_set(struct snd_mixer *m, unsigned dev, unsigned left,
  320                     unsigned right);
  321 static u_int32_t        screamer_setrecsrc(struct snd_mixer *m, u_int32_t src);
  322 
  323 static kobj_method_t screamer_mixer_methods[] = {
  324         KOBJMETHOD(mixer_init,          screamer_init),
  325         KOBJMETHOD(mixer_uninit,        screamer_uninit),
  326         KOBJMETHOD(mixer_reinit,        screamer_reinit),
  327         KOBJMETHOD(mixer_set,           screamer_set),
  328         KOBJMETHOD(mixer_setrecsrc,     screamer_setrecsrc),
  329         KOBJMETHOD_END
  330 };
  331 
  332 MIXER_DECLARE(screamer_mixer);
  333 
  334 static int
  335 screamer_init(struct snd_mixer *m)
  336 {
  337         struct davbus_softc *d;
  338 
  339         d = mix_getdevinfo(m);
  340 
  341         d->read_status = screamer_read_status;
  342         d->set_outputs = screamer_set_outputs;
  343 
  344         mtx_lock(&d->mutex);
  345 
  346         screamer_write_locked(d, SCREAMER_CODEC_ADDR0, SCREAMER_INPUT_CD | 
  347             SCREAMER_DEFAULT_CD_GAIN);
  348 
  349         screamer_set_outputs(d, screamer_read_status(d, 
  350             bus_read_4(d->reg, DAVBUS_CODEC_STATUS)));
  351 
  352         screamer_write_locked(d, SCREAMER_CODEC_ADDR2, 0);
  353         screamer_write_locked(d, SCREAMER_CODEC_ADDR4, 0);
  354         screamer_write_locked(d, SCREAMER_CODEC_ADDR5, 0);
  355         screamer_write_locked(d, SCREAMER_CODEC_ADDR6, 0);
  356 
  357         mtx_unlock(&d->mutex);
  358 
  359         mix_setdevs(m, SOUND_MASK_VOLUME);
  360 
  361         return (0);
  362 }
  363 
  364 static int
  365 screamer_uninit(struct snd_mixer *m)
  366 {
  367         return (0);
  368 }
  369 
  370 static int
  371 screamer_reinit(struct snd_mixer *m)
  372 {
  373         return (0);
  374 }
  375 
  376 static void
  377 screamer_write_locked(struct davbus_softc *d, u_int reg, u_int val)
  378 {
  379         u_int           x;
  380 
  381         KASSERT(val == (val & 0xfff), ("bad val"));
  382 
  383         while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
  384                 DELAY(100);
  385 
  386         x = reg;
  387         x |= SCREAMER_CODEC_EMSEL0;
  388         x |= val;
  389         bus_write_4(d->reg, DAVBUS_CODEC_CTRL, x);
  390 
  391         while (bus_read_4(d->reg, DAVBUS_CODEC_CTRL) & DAVBUS_CODEC_BUSY)
  392                 DELAY(100);
  393 }
  394 
  395 /* Must be called with d->mutex held. */
  396 static void
  397 screamer_set_outputs(struct davbus_softc *d, u_int mask)
  398 {
  399         u_int   x;
  400 
  401         if (mask == d->output_mask) {
  402                 return;
  403         }
  404 
  405         x = SCREAMER_MUTE_SPEAKER | SCREAMER_MUTE_HEADPHONES;
  406 
  407         DPRINTF(("Enabled outputs: "));
  408 
  409         if (mask & (1 << 0)) {
  410                 DPRINTF(("SPEAKER "));
  411                 x &= ~SCREAMER_MUTE_SPEAKER;
  412         }
  413         if (mask & (1 << 1)) {
  414                 DPRINTF(("HEADPHONES "));
  415                 x &= ~SCREAMER_MUTE_HEADPHONES;
  416         }
  417 
  418         DPRINTF(("\n"));
  419 
  420         if (d->device_id == 5 || d->device_id == 11) {
  421                 DPRINTF(("Enabling programmable output.\n"));
  422                 x |= SCREAMER_PROG_OUTPUT0;
  423         }
  424         if (d->device_id == 8 || d->device_id == 11) {
  425                 x &= ~SCREAMER_MUTE_SPEAKER;
  426 
  427                 if (mask & (1 << 0))
  428                         x |= SCREAMER_PROG_OUTPUT1; /* enable speaker. */
  429         }
  430 
  431         screamer_write_locked(d, SCREAMER_CODEC_ADDR1, x);
  432         d->output_mask = mask;
  433 }
  434 
  435 static u_int
  436 screamer_read_status(struct davbus_softc *d, u_int status)
  437 {
  438         int     headphones;
  439 
  440         switch (d->device_id) {
  441         case 5: /* Sawtooth */
  442                 headphones = (status & 0x4);
  443                 break;
  444 
  445         case 8:
  446         case 11: /* iMac DV */
  447                 /* The iMac DV has 2 headphone outputs. */
  448                 headphones = (status & 0x7);
  449                 break;
  450 
  451         default:
  452                 headphones = (status & 0x8);
  453         }
  454 
  455         if (headphones)
  456                 return (1 << 1);
  457         else
  458                 return (1 << 0);
  459 }
  460 
  461 static int
  462 screamer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
  463 {
  464         struct davbus_softc *d;
  465         int lval, rval;
  466 
  467         lval = ((100 - left) * 15 / 100) & 0xf;
  468         rval = ((100 - right) * 15 / 100) & 0xf;
  469         DPRINTF(("volume %d %d\n", lval, rval));
  470 
  471         d = mix_getdevinfo(m);
  472 
  473         switch (dev) {
  474         case SOUND_MIXER_VOLUME:
  475                 mtx_lock(&d->mutex);
  476                 screamer_write_locked(d, SCREAMER_CODEC_ADDR2, (lval << 6) |
  477                     rval);
  478                 screamer_write_locked(d, SCREAMER_CODEC_ADDR4, (lval << 6) | 
  479                     rval);
  480                 mtx_unlock(&d->mutex);
  481 
  482                 return (left | (right << 8));
  483         }
  484 
  485         return (0);
  486 }
  487 
  488 static u_int32_t
  489 screamer_setrecsrc(struct snd_mixer *m, u_int32_t src)
  490 {
  491         return (0);
  492 }
  493 
  494 static int
  495 davbus_attach(device_t self)
  496 {
  497         struct davbus_softc     *sc;
  498         struct resource         *dbdma_irq, *cintr;
  499         void                    *cookie;
  500         char                     compat[64];
  501         int                      rid, oirq, err;
  502 
  503         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO);
  504 
  505         sc->aoa.sc_dev = self;
  506         sc->node = ofw_bus_get_node(self);
  507         sc->soundnode = OF_child(sc->node);
  508 
  509         /* Map the controller register space. */
  510         rid = 0;
  511         sc->reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE);
  512         if (sc->reg == NULL) 
  513                 return (ENXIO);
  514 
  515         /* Map the DBDMA channel register space. */
  516         rid = 1;
  517         sc->aoa.sc_odma = bus_alloc_resource_any(self, SYS_RES_MEMORY, 
  518             &rid, RF_ACTIVE);
  519         if (sc->aoa.sc_odma == NULL)
  520                 return (ENXIO);
  521 
  522         /* Establish the DBDMA channel edge-triggered interrupt. */
  523         rid = 1;
  524         dbdma_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, 
  525             &rid, RF_SHAREABLE | RF_ACTIVE);
  526         if (dbdma_irq == NULL)
  527                 return (ENXIO);
  528 
  529         oirq = rman_get_start(dbdma_irq);
  530 
  531         DPRINTF(("interrupting at irq %d\n", oirq));
  532 
  533         err = powerpc_config_intr(oirq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
  534         if (err != 0)
  535                 return (err);
  536                 
  537         snd_setup_intr(self, dbdma_irq, INTR_MPSAFE, aoa_interrupt,
  538             sc, &cookie);
  539 
  540         /* Now initialize the controller. */
  541 
  542         bzero(compat, sizeof(compat));
  543         OF_getprop(sc->soundnode, "compatible", compat, sizeof(compat));
  544         OF_getprop(sc->soundnode, "device-id", &sc->device_id, sizeof(u_int));
  545 
  546         mtx_init(&sc->mutex, "DAVbus", NULL, MTX_DEF);
  547 
  548         device_printf(self, "codec: <%s>\n", compat);
  549 
  550         /* Setup the control interrupt. */
  551         rid = 0;
  552         cintr = bus_alloc_resource_any(self, SYS_RES_IRQ, 
  553              &rid, RF_SHAREABLE | RF_ACTIVE);
  554         if (cintr != NULL) 
  555                 bus_setup_intr(self, cintr, INTR_TYPE_MISC | INTR_MPSAFE,
  556                     NULL, davbus_cint, sc, &cookie);
  557 
  558         /* Initialize controller registers. */
  559         bus_write_4(sc->reg, DAVBUS_SOUND_CTRL, DAVBUS_INPUT_SUBFRAME0 | 
  560             DAVBUS_OUTPUT_SUBFRAME0 | DAVBUS_RATE_44100 | DAVBUS_INTR_PORTCHG);
  561 
  562         /* Attach DBDMA engine and PCM layer */
  563         err = aoa_attach(sc);
  564         if (err)
  565                 return (err);
  566 
  567         /* Install codec module */
  568         if (strcmp(compat, "screamer") == 0)
  569                 mixer_init(self, &screamer_mixer_class, sc);
  570         else if (strcmp(compat, "burgundy") == 0)
  571                 mixer_init(self, &burgundy_mixer_class, sc);
  572 
  573         return (0);
  574 }
  575 
  576 static void 
  577 davbus_cint(void *ptr)
  578 {
  579         struct davbus_softc *d = ptr;
  580         u_int   reg, status, mask;
  581 
  582         mtx_lock(&d->mutex);
  583 
  584         reg = bus_read_4(d->reg, DAVBUS_SOUND_CTRL);
  585         if (reg & DAVBUS_PORTCHG) {
  586                 
  587                 status = bus_read_4(d->reg, DAVBUS_CODEC_STATUS);
  588                 
  589                 if (d->read_status && d->set_outputs) {
  590                         mask = (*d->read_status)(d, status);
  591                         (*d->set_outputs)(d, mask);
  592                 }
  593 
  594                 /* Clear the interrupt. */
  595                 bus_write_4(d->reg, DAVBUS_SOUND_CTRL, reg);
  596         }
  597 
  598         mtx_unlock(&d->mutex);
  599 }

Cache object: 4fd0bc69870087febf396c9aa90cafa1


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