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/pci/auvia.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 /*      $NetBSD: auvia.c,v 1.36.2.2 2004/09/22 20:58:15 jmc Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Tyler C. Sarna
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * VIA Technologies VT82C686A / VT8233 / VT8235 Southbridge Audio Driver
   41  *
   42  * Documentation links:
   43  *
   44  * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf
   45  * ftp://ftp.alsa-project.org/pub/manuals/general/ac97r21.pdf
   46  * ftp://ftp.alsa-project.org/pub/manuals/ad/AD1881_0.pdf (example AC'97 codec)
   47  */
   48 
   49 #include <sys/cdefs.h>
   50 __KERNEL_RCSID(0, "$NetBSD: auvia.c,v 1.36.2.2 2004/09/22 20:58:15 jmc Exp $");
   51 
   52 #include <sys/param.h>
   53 #include <sys/systm.h>
   54 #include <sys/malloc.h>
   55 #include <sys/device.h>
   56 #include <sys/audioio.h>
   57 
   58 #include <uvm/uvm_extern.h>
   59 
   60 #include <dev/pci/pcidevs.h>
   61 #include <dev/pci/pcivar.h>
   62 
   63 #include <dev/audio_if.h>
   64 #include <dev/mulaw.h>
   65 #include <dev/auconv.h>
   66 
   67 #include <dev/ic/ac97reg.h>
   68 #include <dev/ic/ac97var.h>
   69 
   70 #include <dev/pci/auviavar.h>
   71 
   72 struct auvia_dma {
   73         struct auvia_dma *next;
   74         caddr_t addr;
   75         size_t size;
   76         bus_dmamap_t map;
   77         bus_dma_segment_t seg;
   78 };
   79 
   80 struct auvia_dma_op {
   81         u_int32_t ptr;
   82         u_int32_t flags;
   83 #define AUVIA_DMAOP_EOL         0x80000000
   84 #define AUVIA_DMAOP_FLAG        0x40000000
   85 #define AUVIA_DMAOP_STOP        0x20000000
   86 #define AUVIA_DMAOP_COUNT(x)    ((x)&0x00FFFFFF)
   87 };
   88 
   89 int     auvia_match(struct device *, struct cfdata *, void *);
   90 void    auvia_attach(struct device *, struct device *, void *);
   91 int     auvia_open(void *, int);
   92 void    auvia_close(void *);
   93 int     auvia_query_encoding(void *, struct audio_encoding *);
   94 void    auvia_set_params_sub(struct auvia_softc *, struct auvia_softc_chan *,
   95         struct audio_params *);
   96 int     auvia_set_params(void *, int, int, struct audio_params *,
   97         struct audio_params *);
   98 int     auvia_round_blocksize(void *, int);
   99 int     auvia_halt_output(void *);
  100 int     auvia_halt_input(void *);
  101 int     auvia_getdev(void *, struct audio_device *);
  102 int     auvia_set_port(void *, mixer_ctrl_t *);
  103 int     auvia_get_port(void *, mixer_ctrl_t *);
  104 int     auvia_query_devinfo(void *, mixer_devinfo_t *);
  105 void *  auvia_malloc(void *, int, size_t, struct malloc_type *, int);
  106 void    auvia_free(void *, void *, struct malloc_type *);
  107 size_t  auvia_round_buffersize(void *, int, size_t);
  108 paddr_t auvia_mappage(void *, void *, off_t, int);
  109 int     auvia_get_props(void *);
  110 int     auvia_build_dma_ops(struct auvia_softc *, struct auvia_softc_chan *,
  111         struct auvia_dma *, void *, void *, int);
  112 int     auvia_trigger_output(void *, void *, void *, int, void (*)(void *),
  113         void *, struct audio_params *);
  114 int     auvia_trigger_input(void *, void *, void *, int, void (*)(void *),
  115         void *, struct audio_params *);
  116 
  117 int     auvia_intr __P((void *));
  118 
  119 CFATTACH_DECL(auvia, sizeof (struct auvia_softc),
  120     auvia_match, auvia_attach, NULL, NULL);
  121 
  122 /* VIA VT823xx revision number */
  123 #define VIA_REV_8233C   0x20
  124 #define VIA_REV_8233    0x30
  125 #define VIA_REV_8233A   0x40
  126 #define VIA_REV_8235    0x50
  127 
  128 #define AUVIA_PCICONF_JUNK      0x40
  129 #define         AUVIA_PCICONF_ENABLES    0x00FF0000     /* reg 42 mask */
  130 #define         AUVIA_PCICONF_ACLINKENAB 0x00008000     /* ac link enab */
  131 #define         AUVIA_PCICONF_ACNOTRST   0x00004000     /* ~(ac reset) */
  132 #define         AUVIA_PCICONF_ACSYNC     0x00002000     /* ac sync */
  133 #define         AUVIA_PCICONF_ACVSR      0x00000800     /* var. samp. rate */
  134 #define         AUVIA_PCICONF_ACSGD      0x00000400     /* SGD enab */
  135 #define         AUVIA_PCICONF_ACFM       0x00000200     /* FM enab */
  136 #define         AUVIA_PCICONF_ACSB       0x00000100     /* SB enab */
  137 #define         AUVIA_PCICONF_PRIVALID   0x00000001     /* primary codec rdy */
  138 
  139 #define AUVIA_PLAY_BASE                 0x00
  140 #define AUVIA_RECORD_BASE               0x10
  141 
  142 /* *_RP_* are offsets from AUVIA_PLAY_BASE or AUVIA_RECORD_BASE */
  143 #define AUVIA_RP_STAT                   0x00
  144 #define         AUVIA_RPSTAT_INTR               0x03
  145 #define AUVIA_RP_CONTROL                0x01
  146 #define         AUVIA_RPCTRL_START              0x80
  147 #define         AUVIA_RPCTRL_TERMINATE          0x40
  148 #define         AUVIA_RPCTRL_AUTOSTART          0x20
  149 /* The following are 8233 specific */
  150 #define         AUVIA_RPCTRL_STOP               0x04
  151 #define         AUVIA_RPCTRL_EOL                0x02
  152 #define         AUVIA_RPCTRL_FLAG               0x01
  153 #define AUVIA_RP_MODE                   0x02            /* 82c686 specific */
  154 #define         AUVIA_RPMODE_INTR_FLAG          0x01
  155 #define         AUVIA_RPMODE_INTR_EOL           0x02
  156 #define         AUVIA_RPMODE_STEREO             0x10
  157 #define         AUVIA_RPMODE_16BIT              0x20
  158 #define         AUVIA_RPMODE_AUTOSTART          0x80
  159 #define AUVIA_RP_DMAOPS_BASE            0x04
  160 
  161 #define VIA8233_RP_DXS_LVOL             0x02
  162 #define VIA8233_RP_DXS_RVOL             0x03
  163 #define VIA8233_RP_RATEFMT              0x08
  164 #define         VIA8233_RATEFMT_48K             0xfffff
  165 #define         VIA8233_RATEFMT_STEREO          0x00100000
  166 #define         VIA8233_RATEFMT_16BIT           0x00200000
  167 
  168 #define VIA_RP_DMAOPS_COUNT             0x0c
  169 
  170 #define VIA8233_MP_BASE                 0x40
  171         /* STAT, CONTROL, DMAOPS_BASE, DMAOPS_COUNT are valid */
  172 #define VIA8233_OFF_MP_FORMAT           0x02
  173 #define         VIA8233_MP_FORMAT_8BIT          0x00
  174 #define         VIA8233_MP_FORMAT_16BIT         0x80
  175 #define         VIA8233_MP_FORMAT_CHANNLE_MASK  0x70 /* 1, 2, 4, 6 */
  176 #define VIA8233_OFF_MP_SCRATCH          0x03
  177 #define VIA8233_OFF_MP_STOP             0x08
  178 
  179 #define AUVIA_CODEC_CTL                 0x80
  180 #define         AUVIA_CODEC_READ                0x00800000
  181 #define         AUVIA_CODEC_BUSY                0x01000000
  182 #define         AUVIA_CODEC_PRIVALID            0x02000000
  183 #define         AUVIA_CODEC_INDEX(x)            ((x)<<16)
  184 
  185 #define CH_WRITE1(sc, ch, off, v)       \
  186         bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (ch)->sc_base + (off), v)
  187 #define CH_WRITE4(sc, ch, off, v)       \
  188         bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (ch)->sc_base + (off), v)
  189 #define CH_READ1(sc, ch, off)           \
  190         bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (ch)->sc_base + (off))
  191 #define CH_READ4(sc, ch, off)           \
  192         bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (ch)->sc_base + (off))
  193 
  194 #define TIMEOUT 50
  195 
  196 struct audio_hw_if auvia_hw_if = {
  197         auvia_open,
  198         auvia_close,
  199         NULL, /* drain */
  200         auvia_query_encoding,
  201         auvia_set_params,
  202         auvia_round_blocksize,
  203         NULL, /* commit_settings */
  204         NULL, /* init_output */
  205         NULL, /* init_input */
  206         NULL, /* start_output */
  207         NULL, /* start_input */
  208         auvia_halt_output,
  209         auvia_halt_input,
  210         NULL, /* speaker_ctl */
  211         auvia_getdev,
  212         NULL, /* setfd */
  213         auvia_set_port,
  214         auvia_get_port,
  215         auvia_query_devinfo,
  216         auvia_malloc,
  217         auvia_free,
  218         auvia_round_buffersize,
  219         auvia_mappage,
  220         auvia_get_props,
  221         auvia_trigger_output,
  222         auvia_trigger_input,
  223         NULL, /* dev_ioctl */
  224 };
  225 
  226 int     auvia_attach_codec(void *, struct ac97_codec_if *);
  227 int     auvia_write_codec(void *, u_int8_t, u_int16_t);
  228 int     auvia_read_codec(void *, u_int8_t, u_int16_t *);
  229 int     auvia_reset_codec(void *);
  230 int     auvia_waitready_codec(struct auvia_softc *sc);
  231 int     auvia_waitvalid_codec(struct auvia_softc *sc);
  232 
  233 
  234 int
  235 auvia_match(struct device *parent, struct cfdata *match, void *aux)
  236 {
  237         struct pci_attach_args *pa = (struct pci_attach_args *) aux;
  238 
  239         if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
  240                 return 0;
  241         switch (PCI_PRODUCT(pa->pa_id)) {
  242         case PCI_PRODUCT_VIATECH_VT82C686A_AC97:
  243         case PCI_PRODUCT_VIATECH_VT8233_AC97:
  244                 break;
  245         default:
  246                 return 0;
  247         }
  248 
  249         return 1;
  250 }
  251 
  252 
  253 void
  254 auvia_attach(struct device *parent, struct device *self, void *aux)
  255 {
  256         struct pci_attach_args *pa = aux;
  257         struct auvia_softc *sc = (struct auvia_softc *) self;
  258         const char *intrstr = NULL;
  259         pci_chipset_tag_t pc = pa->pa_pc;
  260         pcitag_t pt = pa->pa_tag;
  261         pci_intr_handle_t ih;
  262         bus_size_t iosize;
  263         pcireg_t pr;
  264         int r;
  265         const char *revnum = NULL; /* VT823xx revision number */
  266 
  267         aprint_naive(": Audio controller\n");
  268 
  269         sc->sc_play.sc_base = AUVIA_PLAY_BASE;
  270         sc->sc_record.sc_base = AUVIA_RECORD_BASE;
  271         if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT8233_AC97) {
  272                 sc->sc_flags |= AUVIA_FLAGS_VT8233;
  273                 sc->sc_play.sc_base = VIA8233_MP_BASE;
  274         }
  275 
  276         if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
  277                 &sc->sc_ioh, NULL, &iosize)) {
  278                 aprint_error(": can't map i/o space\n");
  279                 return;
  280         }
  281 
  282         sc->sc_dmat = pa->pa_dmat;
  283         sc->sc_pc = pc;
  284         sc->sc_pt = pt;
  285 
  286         r = PCI_REVISION(pa->pa_class);
  287         if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
  288                 sprintf(sc->sc_revision, "0x%02X", r);
  289                 switch(r) {
  290                 case VIA_REV_8233C:
  291                         /* 2 rec, 4 pb, 1 multi-pb */
  292                         revnum = "3C";
  293                         break;
  294                 case VIA_REV_8233:
  295                         /* 2 rec, 4 pb, 1 multi-pb, spdif */
  296                         revnum = "3";
  297                         break;
  298                 case VIA_REV_8233A:
  299                         /* 1 rec, 1 multi-pb, spdif */
  300                         revnum = "3A";
  301                         break;
  302                 default:
  303                         break;
  304                 }
  305                 if (r >= VIA_REV_8235) /* 2 rec, 4 pb, 1 multi-pb, spdif */
  306                         revnum = "5";
  307                 aprint_normal(": VIA VT823%s AC'97 (rev %s)\n",
  308                         revnum, sc->sc_revision);
  309         } else {
  310                 sc->sc_revision[1] = '\0';
  311                 if (r == 0x20) {
  312                         sc->sc_revision[0] = 'H';
  313                 } else if ((r >= 0x10) && (r <= 0x14)) {
  314                         sc->sc_revision[0] = 'A' + (r - 0x10);
  315                 } else {
  316                         sprintf(sc->sc_revision, "0x%02X", r);
  317                 }
  318 
  319                 aprint_normal(": VIA VT82C686A AC'97 Audio (rev %s)\n",
  320                        sc->sc_revision);
  321         }
  322 
  323         if (pci_intr_map(pa, &ih)) {
  324                 aprint_error(": couldn't map interrupt\n");
  325                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  326                 return;
  327         }
  328         intrstr = pci_intr_string(pc, ih);
  329 
  330         sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO, auvia_intr, sc);
  331         if (sc->sc_ih == NULL) {
  332                 aprint_error("%s: couldn't establish interrupt",
  333                     sc->sc_dev.dv_xname);
  334                 if (intrstr != NULL)
  335                         aprint_normal(" at %s", intrstr);
  336                 aprint_normal("\n");
  337                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  338                 return;
  339         }
  340 
  341         aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
  342 
  343         /* disable SBPro compat & others */
  344         pr = pci_conf_read(pc, pt, AUVIA_PCICONF_JUNK);
  345 
  346         pr &= ~AUVIA_PCICONF_ENABLES; /* clear compat function enables */
  347         /* XXX what to do about MIDI, FM, joystick? */
  348 
  349         pr |= (AUVIA_PCICONF_ACLINKENAB | AUVIA_PCICONF_ACNOTRST
  350                 | AUVIA_PCICONF_ACVSR | AUVIA_PCICONF_ACSGD);
  351 
  352         pr &= ~(AUVIA_PCICONF_ACFM | AUVIA_PCICONF_ACSB);
  353 
  354         pci_conf_write(pc, pt, AUVIA_PCICONF_JUNK, pr);
  355 
  356         sc->host_if.arg = sc;
  357         sc->host_if.attach = auvia_attach_codec;
  358         sc->host_if.read = auvia_read_codec;
  359         sc->host_if.write = auvia_write_codec;
  360         sc->host_if.reset = auvia_reset_codec;
  361 
  362         if ((r = ac97_attach(&sc->host_if)) != 0) {
  363                 aprint_error("%s: can't attach codec (error 0x%X)\n",
  364                         sc->sc_dev.dv_xname, r);
  365                 pci_intr_disestablish(pc, sc->sc_ih);
  366                 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize);
  367                 return;
  368         }
  369 
  370         audio_attach_mi(&auvia_hw_if, sc, &sc->sc_dev);
  371 }
  372 
  373 
  374 int
  375 auvia_attach_codec(void *addr, struct ac97_codec_if *cif)
  376 {
  377         struct auvia_softc *sc = addr;
  378 
  379         sc->codec_if = cif;
  380 
  381         return 0;
  382 }
  383 
  384 
  385 int
  386 auvia_reset_codec(void *addr)
  387 {
  388         int i;
  389         struct auvia_softc *sc = addr;
  390         pcireg_t r;
  391 
  392         /* perform a codec cold reset */
  393 
  394         r = pci_conf_read(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK);
  395 
  396         r &= ~AUVIA_PCICONF_ACNOTRST;   /* enable RESET (active low) */
  397         pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
  398         delay(2);
  399 
  400         r |= AUVIA_PCICONF_ACNOTRST;    /* disable RESET (inactive high) */
  401         pci_conf_write(sc->sc_pc, sc->sc_pt, AUVIA_PCICONF_JUNK, r);
  402         delay(200);
  403 
  404         for (i = 500000; i != 0 && !(pci_conf_read(sc->sc_pc, sc->sc_pt,
  405                 AUVIA_PCICONF_JUNK) & AUVIA_PCICONF_PRIVALID); i--)
  406                 DELAY(1);
  407         if (i == 0) {
  408                 printf("%s: codec reset timed out\n", sc->sc_dev.dv_xname);
  409                 return ETIMEDOUT;
  410         }
  411         return 0;
  412 }
  413 
  414 
  415 int
  416 auvia_waitready_codec(struct auvia_softc *sc)
  417 {
  418         int i;
  419 
  420         /* poll until codec not busy */
  421         for (i = 0; (i < TIMEOUT) && (bus_space_read_4(sc->sc_iot, sc->sc_ioh,
  422                 AUVIA_CODEC_CTL) & AUVIA_CODEC_BUSY); i++)
  423                 delay(1);
  424         if (i >= TIMEOUT) {
  425                 printf("%s: codec busy\n", sc->sc_dev.dv_xname);
  426                 return 1;
  427         }
  428 
  429         return 0;
  430 }
  431 
  432 
  433 int
  434 auvia_waitvalid_codec(struct auvia_softc *sc)
  435 {
  436         int i;
  437 
  438         /* poll until codec valid */
  439         for (i = 0; (i < TIMEOUT) && !(bus_space_read_4(sc->sc_iot, sc->sc_ioh,
  440                 AUVIA_CODEC_CTL) & AUVIA_CODEC_PRIVALID); i++)
  441                         delay(1);
  442         if (i >= TIMEOUT) {
  443                 printf("%s: codec invalid\n", sc->sc_dev.dv_xname);
  444                 return 1;
  445         }
  446 
  447         return 0;
  448 }
  449 
  450 
  451 int
  452 auvia_write_codec(void *addr, u_int8_t reg, u_int16_t val)
  453 {
  454         struct auvia_softc *sc = addr;
  455 
  456         if (auvia_waitready_codec(sc))
  457                 return 1;
  458 
  459         bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
  460                 AUVIA_CODEC_PRIVALID | AUVIA_CODEC_INDEX(reg) | val);
  461 
  462         return 0;
  463 }
  464 
  465 
  466 int
  467 auvia_read_codec(void *addr, u_int8_t reg, u_int16_t *val)
  468 {
  469         struct auvia_softc *sc = addr;
  470 
  471         if (auvia_waitready_codec(sc))
  472                 return 1;
  473 
  474         bus_space_write_4(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL,
  475                 AUVIA_CODEC_PRIVALID | AUVIA_CODEC_READ | AUVIA_CODEC_INDEX(reg));
  476 
  477         if (auvia_waitready_codec(sc))
  478                 return 1;
  479 
  480         if (auvia_waitvalid_codec(sc))
  481                 return 1;
  482 
  483         *val = bus_space_read_2(sc->sc_iot, sc->sc_ioh, AUVIA_CODEC_CTL);
  484 
  485         return 0;
  486 }
  487 
  488 
  489 int
  490 auvia_open(void *addr, int flags)
  491 {
  492         return 0;
  493 }
  494 
  495 
  496 void
  497 auvia_close(void *addr)
  498 {
  499         struct auvia_softc *sc = addr;
  500 
  501         auvia_halt_output(sc);
  502         auvia_halt_input(sc);
  503 
  504         sc->sc_play.sc_intr = NULL;
  505         sc->sc_record.sc_intr = NULL;
  506 }
  507 
  508 
  509 int
  510 auvia_query_encoding(void *addr, struct audio_encoding *fp)
  511 {
  512         switch (fp->index) {
  513         case 0:
  514                 strcpy(fp->name, AudioEulinear);
  515                 fp->encoding = AUDIO_ENCODING_ULINEAR;
  516                 fp->precision = 8;
  517                 fp->flags = 0;
  518                 return (0);
  519         case 1:
  520                 strcpy(fp->name, AudioEmulaw);
  521                 fp->encoding = AUDIO_ENCODING_ULAW;
  522                 fp->precision = 8;
  523                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  524                 return (0);
  525         case 2:
  526                 strcpy(fp->name, AudioEalaw);
  527                 fp->encoding = AUDIO_ENCODING_ALAW;
  528                 fp->precision = 8;
  529                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  530                 return (0);
  531         case 3:
  532                 strcpy(fp->name, AudioEslinear);
  533                 fp->encoding = AUDIO_ENCODING_SLINEAR;
  534                 fp->precision = 8;
  535                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  536                 return (0);
  537         case 4:
  538                 strcpy(fp->name, AudioEslinear_le);
  539                 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
  540                 fp->precision = 16;
  541                 fp->flags = 0;
  542                 return (0);
  543         case 5:
  544                 strcpy(fp->name, AudioEulinear_le);
  545                 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
  546                 fp->precision = 16;
  547                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  548                 return (0);
  549         case 6:
  550                 strcpy(fp->name, AudioEslinear_be);
  551                 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
  552                 fp->precision = 16;
  553                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  554                 return (0);
  555         case 7:
  556                 strcpy(fp->name, AudioEulinear_be);
  557                 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
  558                 fp->precision = 16;
  559                 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
  560                 return (0);
  561         default:
  562                 return (EINVAL);
  563         }
  564 }
  565 
  566 void
  567 auvia_set_params_sub(struct auvia_softc *sc, struct auvia_softc_chan *ch,
  568                      struct audio_params *p)
  569 {
  570         u_int32_t v;
  571         u_int16_t regval;
  572 
  573         if (!(sc->sc_flags & AUVIA_FLAGS_VT8233)) {
  574                 regval = (p->channels == 2 ? AUVIA_RPMODE_STEREO : 0)
  575                         | (p->precision * p->factor == 16 ?
  576                                 AUVIA_RPMODE_16BIT : 0)
  577                         | AUVIA_RPMODE_INTR_FLAG | AUVIA_RPMODE_INTR_EOL
  578                         | AUVIA_RPMODE_AUTOSTART;
  579                 ch->sc_reg = regval;
  580         } else if (ch->sc_base != VIA8233_MP_BASE) {
  581                 v = CH_READ4(sc, ch, VIA8233_RP_RATEFMT);
  582                 v &= ~(VIA8233_RATEFMT_48K | VIA8233_RATEFMT_STEREO
  583                         | VIA8233_RATEFMT_16BIT);
  584 
  585                 v |= VIA8233_RATEFMT_48K * (p->sample_rate / 20)
  586                         / (48000 / 20);
  587                 if (p->channels == 2)
  588                         v |= VIA8233_RATEFMT_STEREO;
  589                 if (p->precision == 16)
  590                         v |= VIA8233_RATEFMT_16BIT;
  591 
  592                 CH_WRITE4(sc, ch, VIA8233_RP_RATEFMT, v);
  593         } else {
  594                 static const u_int32_t slottab[7] =
  595                         { 0, 0xff000011, 0xff000021, 0,
  596                           0xff004321, 0, 0xff436521};
  597 
  598                 regval = (p->hw_precision == 16
  599                         ? VIA8233_MP_FORMAT_16BIT : VIA8233_MP_FORMAT_8BIT)
  600                         | (p->hw_channels << 4);
  601                 CH_WRITE1(sc, ch, VIA8233_OFF_MP_FORMAT, regval);
  602                 CH_WRITE4(sc, ch, VIA8233_OFF_MP_STOP, slottab[p->hw_channels]);
  603         }
  604 }
  605 
  606 int
  607 auvia_set_params(void *addr, int setmode, int usemode,
  608         struct audio_params *play, struct audio_params *rec)
  609 {
  610         struct auvia_softc *sc = addr;
  611         struct auvia_softc_chan *ch;
  612         struct audio_params *p;
  613         struct ac97_codec_if* codec;
  614         int reg, mode;
  615         u_int16_t ext_id;
  616 
  617         codec = sc->codec_if;
  618         /* for mode in (RECORD, PLAY) */
  619         for (mode = AUMODE_RECORD; mode != -1;
  620              mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
  621                 if ((setmode & mode) == 0)
  622                         continue;
  623 
  624                 if (mode == AUMODE_PLAY ) {
  625                         p = play;
  626                         ch = &sc->sc_play;
  627                         reg = AC97_REG_PCM_FRONT_DAC_RATE;
  628                 } else {
  629                         p = rec;
  630                         ch = &sc->sc_record;
  631                         reg = AC97_REG_PCM_LR_ADC_RATE;
  632                 }
  633 
  634                 if (ch->sc_base == VIA8233_MP_BASE && mode == AUMODE_PLAY) {
  635                         ext_id = codec->vtbl->get_extcaps(codec);
  636                         if (p->channels == 1) {
  637                                 /* ok */
  638                         } else if (p->channels == 2) {
  639                                 /* ok */
  640                         } else if (p->channels == 4
  641                                 && ext_id & AC97_EXT_AUDIO_SDAC) {
  642                                 /* ok */
  643 #define BITS_6CH        (AC97_EXT_AUDIO_SDAC | AC97_EXT_AUDIO_CDAC | AC97_EXT_AUDIO_LDAC)
  644                         } else if (p->channels == 6
  645                                 && (ext_id & BITS_6CH) == BITS_6CH) {
  646                                 /* ok */
  647                         } else {
  648                                 return (EINVAL);
  649                         }
  650                 } else {
  651                         if (p->channels != 1 && p->channels != 2)
  652                                 return (EINVAL);
  653                 }
  654                 if (p->sample_rate < 4000 || p->sample_rate > 48000 ||
  655                     (p->precision != 8 && p->precision != 16))
  656                         return (EINVAL);
  657 
  658                 if (IS_FIXED_RATE(codec)) {
  659                         /* Enable aurateconv */
  660                         p->hw_sample_rate = AC97_SINGLE_RATE;
  661                 } else {
  662                         if (codec->vtbl->set_rate(codec, reg, &p->sample_rate))
  663                                 return (EINVAL);
  664                         reg = AC97_REG_PCM_SURR_DAC_RATE;
  665                         if (p->channels >= 4
  666                             && codec->vtbl->set_rate(codec, reg,
  667                                                      &p->sample_rate))
  668                                 return (EINVAL);
  669                         reg = AC97_REG_PCM_LFE_DAC_RATE;
  670                         if (p->channels == 6
  671                             && codec->vtbl->set_rate(codec, reg,
  672                                                      &p->sample_rate))
  673                                 return (EINVAL);
  674                 }
  675 
  676                 p->factor = 1;
  677                 p->sw_code = 0;
  678                 switch (p->encoding) {
  679                 case AUDIO_ENCODING_SLINEAR_BE:
  680                         if (p->precision == 16) {
  681                                 p->sw_code = swap_bytes;
  682                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  683                         } else {
  684                                 p->sw_code = change_sign8;
  685                                 p->hw_encoding = AUDIO_ENCODING_ULINEAR;
  686                         }
  687                         break;
  688                 case AUDIO_ENCODING_SLINEAR_LE:
  689                         if (p->precision != 16) {
  690                                 p->sw_code = change_sign8;
  691                                 p->hw_encoding = AUDIO_ENCODING_ULINEAR;
  692                         }
  693                         break;
  694                 case AUDIO_ENCODING_ULINEAR_BE:
  695                         if (p->precision == 16) {
  696                                 if (mode == AUMODE_PLAY)
  697                                         p->sw_code = swap_bytes_change_sign16_le;
  698                                 else
  699                                         p->sw_code = change_sign16_swap_bytes_le;
  700                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  701                         }
  702                         break;
  703                 case AUDIO_ENCODING_ULINEAR_LE:
  704                         if (p->precision == 16) {
  705                                 p->sw_code = change_sign16_le;
  706                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  707                         }
  708                         break;
  709                 case AUDIO_ENCODING_ULAW:
  710                         if (p->precision != 8)
  711                                 return (EINVAL);
  712                         if (mode == AUMODE_PLAY) {
  713                                 p->factor = 2;
  714                                 p->sw_code = mulaw_to_slinear16_le;
  715                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  716                                 p->hw_precision = 16;
  717                         } else if (!IS_FIXED_RATE(codec)) {
  718                                 p->sw_code = ulinear8_to_mulaw;
  719                                 p->hw_encoding = AUDIO_ENCODING_ULINEAR;
  720                         } else {
  721                                 /* aurateconv supports no 8 bit PCM */
  722                                 p->factor = 2;
  723                                 p->sw_code = slinear16_to_mulaw_le;
  724                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  725                                 p->hw_precision = 16;
  726                         }
  727                         break;
  728                 case AUDIO_ENCODING_ALAW:
  729                         if (p->precision != 8)
  730                                 return (EINVAL);
  731                         if (mode == AUMODE_PLAY) {
  732                                 p->factor = 2;
  733                                 p->sw_code = alaw_to_slinear16_le;
  734                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  735                                 p->hw_precision = 16;
  736                         } else if (!IS_FIXED_RATE(codec)) {
  737                                 p->sw_code = ulinear8_to_alaw;
  738                                 p->hw_encoding = AUDIO_ENCODING_ULINEAR;
  739                         } else {
  740                                 /* aurateconv supports no 8 bit PCM */
  741                                 p->factor = 2;
  742                                 p->sw_code = slinear16_to_alaw_le;
  743                                 p->hw_encoding = AUDIO_ENCODING_SLINEAR_LE;
  744                                 p->hw_precision = 16;
  745                         }
  746                         break;
  747                 default:
  748                         return (EINVAL);
  749                 }
  750                 auvia_set_params_sub(sc, ch, p);
  751         }
  752 
  753         return 0;
  754 }
  755 
  756 
  757 int
  758 auvia_round_blocksize(void *addr, int blk)
  759 {
  760         struct auvia_softc *sc = addr;
  761 
  762         /* XXX VT823x might have the limitation of dma_ops size */
  763         if (sc->sc_flags & AUVIA_FLAGS_VT8233 && blk < 288)
  764                 blk = 288;
  765 
  766         return (blk & -32);
  767 }
  768 
  769 
  770 int
  771 auvia_halt_output(void *addr)
  772 {
  773         struct auvia_softc *sc = addr;
  774         struct auvia_softc_chan *ch = &(sc->sc_play);
  775 
  776         CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
  777         return 0;
  778 }
  779 
  780 
  781 int
  782 auvia_halt_input(void *addr)
  783 {
  784         struct auvia_softc *sc = addr;
  785         struct auvia_softc_chan *ch = &(sc->sc_record);
  786 
  787         CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_TERMINATE);
  788         return 0;
  789 }
  790 
  791 
  792 int
  793 auvia_getdev(void *addr, struct audio_device *retp)
  794 {
  795         struct auvia_softc *sc = addr;
  796 
  797         if (retp) {
  798                 if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
  799                         strncpy(retp->name, "VIA VT8233/8235",
  800                                 sizeof(retp->name));
  801                 } else {
  802                         strncpy(retp->name, "VIA VT82C686A",
  803                                 sizeof(retp->name));
  804                 }
  805                 strncpy(retp->version, sc->sc_revision, sizeof(retp->version));
  806                 strncpy(retp->config, "auvia", sizeof(retp->config));
  807         }
  808 
  809         return 0;
  810 }
  811 
  812 
  813 int
  814 auvia_set_port(void *addr, mixer_ctrl_t *cp)
  815 {
  816         struct auvia_softc *sc = addr;
  817 
  818         return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
  819 }
  820 
  821 
  822 int
  823 auvia_get_port(void *addr, mixer_ctrl_t *cp)
  824 {
  825         struct auvia_softc *sc = addr;
  826 
  827         return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
  828 }
  829 
  830 
  831 int
  832 auvia_query_devinfo(void *addr, mixer_devinfo_t *dip)
  833 {
  834         struct auvia_softc *sc = addr;
  835 
  836         return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip));
  837 }
  838 
  839 
  840 void *
  841 auvia_malloc(void *addr, int direction, size_t size, struct malloc_type * pool,
  842     int flags)
  843 {
  844         struct auvia_softc *sc = addr;
  845         struct auvia_dma *p;
  846         int error;
  847         int rseg;
  848 
  849         p = malloc(sizeof(*p), pool, flags);
  850         if (!p)
  851                 return 0;
  852 
  853         p->size = size;
  854         if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &p->seg,
  855                                       1, &rseg, BUS_DMA_NOWAIT)) != 0) {
  856                 printf("%s: unable to allocate DMA, error = %d\n",
  857                        sc->sc_dev.dv_xname, error);
  858                 goto fail_alloc;
  859         }
  860 
  861         if ((error = bus_dmamem_map(sc->sc_dmat, &p->seg, rseg, size, &p->addr,
  862                                     BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  863                 printf("%s: unable to map DMA, error = %d\n",
  864                        sc->sc_dev.dv_xname, error);
  865                 goto fail_map;
  866         }
  867 
  868         if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
  869                                        BUS_DMA_NOWAIT, &p->map)) != 0) {
  870                 printf("%s: unable to create DMA map, error = %d\n",
  871                        sc->sc_dev.dv_xname, error);
  872                 goto fail_create;
  873         }
  874 
  875         if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, size, NULL,
  876                                      BUS_DMA_NOWAIT)) != 0) {
  877                 printf("%s: unable to load DMA map, error = %d\n",
  878                        sc->sc_dev.dv_xname, error);
  879                 goto fail_load;
  880         }
  881 
  882         p->next = sc->sc_dmas;
  883         sc->sc_dmas = p;
  884 
  885         return p->addr;
  886 
  887 
  888 fail_load:
  889         bus_dmamap_destroy(sc->sc_dmat, p->map);
  890 fail_create:
  891         bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
  892 fail_map:
  893         bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
  894 fail_alloc:
  895         free(p, pool);
  896         return 0;
  897 }
  898 
  899 
  900 void
  901 auvia_free(void *addr, void *ptr, struct malloc_type *pool)
  902 {
  903         struct auvia_softc *sc = addr;
  904         struct auvia_dma **pp, *p;
  905 
  906         for (pp = &(sc->sc_dmas); (p = *pp) != NULL; pp = &p->next)
  907                 if (p->addr == ptr) {
  908                         bus_dmamap_unload(sc->sc_dmat, p->map);
  909                         bus_dmamap_destroy(sc->sc_dmat, p->map);
  910                         bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
  911                         bus_dmamem_free(sc->sc_dmat, &p->seg, 1);
  912 
  913                         *pp = p->next;
  914                         free(p, pool);
  915                         return;
  916                 }
  917 
  918         panic("auvia_free: trying to free unallocated memory");
  919 }
  920 
  921 
  922 size_t
  923 auvia_round_buffersize(void *addr, int direction, size_t size)
  924 {
  925         return size;
  926 }
  927 
  928 
  929 paddr_t
  930 auvia_mappage(void *addr, void *mem, off_t off, int prot)
  931 {
  932         struct auvia_softc *sc = addr;
  933         struct auvia_dma *p;
  934 
  935         if (off < 0)
  936                 return -1;
  937 
  938         for (p = sc->sc_dmas; p && p->addr != mem; p = p->next)
  939                 ;
  940 
  941         if (!p)
  942                 return -1;
  943 
  944         return bus_dmamem_mmap(sc->sc_dmat, &p->seg, 1, off, prot,
  945                BUS_DMA_WAITOK);
  946 }
  947 
  948 
  949 int
  950 auvia_get_props(void *addr)
  951 {
  952         struct auvia_softc *sc = addr;
  953         int props;
  954 
  955         props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
  956         /*
  957          * Even if the codec is fixed-rate, set_param() succeeds for any sample
  958          * rate because of aurateconv.  Applications can't know what rate the
  959          * device can process in the case of mmap().
  960          */
  961         if (!IS_FIXED_RATE(sc->codec_if))
  962                 props |= AUDIO_PROP_MMAP;
  963         return props;
  964 }
  965 
  966 
  967 int
  968 auvia_build_dma_ops(struct auvia_softc *sc, struct auvia_softc_chan *ch,
  969         struct auvia_dma *p, void *start, void *end, int blksize)
  970 {
  971         struct auvia_dma_op *op;
  972         struct auvia_dma *dp;
  973         bus_addr_t s;
  974         size_t l;
  975         int segs;
  976 
  977         s = p->map->dm_segs[0].ds_addr;
  978         l = ((char *)end - (char *)start);
  979         segs = (l + blksize - 1) / blksize;
  980 
  981         if (segs > (ch->sc_dma_op_count)) {
  982                 /* if old list was too small, free it */
  983                 if (ch->sc_dma_ops) {
  984                         auvia_free(sc, ch->sc_dma_ops, M_DEVBUF);
  985                 }
  986 
  987                 ch->sc_dma_ops = auvia_malloc(sc, 0,
  988                         sizeof(struct auvia_dma_op) * segs, M_DEVBUF, M_WAITOK);
  989 
  990                 if (ch->sc_dma_ops == NULL) {
  991                         printf("%s: couldn't build dmaops\n", sc->sc_dev.dv_xname);
  992                         return 1;
  993                 }
  994 
  995                 for (dp = sc->sc_dmas;
  996                         dp && dp->addr != (void *)(ch->sc_dma_ops);
  997                         dp = dp->next)
  998                                 ;
  999 
 1000                 if (!dp)
 1001                         panic("%s: build_dma_ops: where'd my memory go??? "
 1002                                 "address (%p)\n", sc->sc_dev.dv_xname,
 1003                                 ch->sc_dma_ops);
 1004 
 1005                 ch->sc_dma_op_count = segs;
 1006                 ch->sc_dma_ops_dma = dp;
 1007         }
 1008 
 1009         dp = ch->sc_dma_ops_dma;
 1010         op = ch->sc_dma_ops;
 1011 
 1012         while (l) {
 1013                 op->ptr = s;
 1014                 l = l - blksize;
 1015                 if (!l) {
 1016                         /* if last block */
 1017                         op->flags = AUVIA_DMAOP_EOL | blksize;
 1018                 } else {
 1019                         op->flags = AUVIA_DMAOP_FLAG | blksize;
 1020                 }
 1021                 s += blksize;
 1022                 op++;
 1023         }
 1024 
 1025         return 0;
 1026 }
 1027 
 1028 
 1029 int
 1030 auvia_trigger_output(void *addr, void *start, void *end,
 1031         int blksize, void (*intr)(void *), void *arg,
 1032         struct audio_params *param)
 1033 {
 1034         struct auvia_softc *sc = addr;
 1035         struct auvia_softc_chan *ch = &(sc->sc_play);
 1036         struct auvia_dma *p;
 1037 
 1038         for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
 1039                 ;
 1040 
 1041         if (!p)
 1042                 panic("auvia_trigger_output: request with bad start "
 1043                         "address (%p)", start);
 1044 
 1045         if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
 1046                 return 1;
 1047         }
 1048 
 1049         ch->sc_intr = intr;
 1050         ch->sc_arg = arg;
 1051 
 1052         CH_WRITE4(sc, ch, AUVIA_RP_DMAOPS_BASE,
 1053                 ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
 1054 
 1055         if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
 1056                 if (ch->sc_base != VIA8233_MP_BASE) {
 1057                         CH_WRITE1(sc, ch, VIA8233_RP_DXS_LVOL, 0);
 1058                         CH_WRITE1(sc, ch, VIA8233_RP_DXS_RVOL, 0);
 1059                 }
 1060                 CH_WRITE1(sc, ch, AUVIA_RP_CONTROL,
 1061                         AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
 1062                         AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
 1063         } else {
 1064                 CH_WRITE1(sc, ch, AUVIA_RP_MODE, ch->sc_reg);
 1065                 CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
 1066         }
 1067 
 1068         return 0;
 1069 }
 1070 
 1071 
 1072 int
 1073 auvia_trigger_input(void *addr, void *start, void *end,
 1074         int blksize, void (*intr)(void *), void *arg,
 1075         struct audio_params *param)
 1076 {
 1077         struct auvia_softc *sc = addr;
 1078         struct auvia_softc_chan *ch = &(sc->sc_record);
 1079         struct auvia_dma *p;
 1080 
 1081         for (p = sc->sc_dmas; p && p->addr != start; p = p->next)
 1082                 ;
 1083 
 1084         if (!p)
 1085                 panic("auvia_trigger_input: request with bad start "
 1086                         "address (%p)", start);
 1087 
 1088         if (auvia_build_dma_ops(sc, ch, p, start, end, blksize)) {
 1089                 return 1;
 1090         }
 1091 
 1092         ch->sc_intr = intr;
 1093         ch->sc_arg = arg;
 1094 
 1095         CH_WRITE4(sc, ch, AUVIA_RP_DMAOPS_BASE,
 1096                   ch->sc_dma_ops_dma->map->dm_segs[0].ds_addr);
 1097 
 1098         if (sc->sc_flags & AUVIA_FLAGS_VT8233) {
 1099                 CH_WRITE1(sc, ch, VIA8233_RP_DXS_LVOL, 0);
 1100                 CH_WRITE1(sc, ch, VIA8233_RP_DXS_RVOL, 0);
 1101                 CH_WRITE1(sc, ch, AUVIA_RP_CONTROL,
 1102                         AUVIA_RPCTRL_START | AUVIA_RPCTRL_AUTOSTART |
 1103                         AUVIA_RPCTRL_STOP  | AUVIA_RPCTRL_EOL | AUVIA_RPCTRL_FLAG);
 1104         } else {
 1105                 CH_WRITE1(sc, ch, AUVIA_RP_MODE, ch->sc_reg);
 1106                 CH_WRITE1(sc, ch, AUVIA_RP_CONTROL, AUVIA_RPCTRL_START);
 1107         }
 1108 
 1109         return 0;
 1110 }
 1111 
 1112 
 1113 int
 1114 auvia_intr(void *arg)
 1115 {
 1116         struct auvia_softc *sc = arg;
 1117         struct auvia_softc_chan *ch;
 1118         u_int8_t r;
 1119         int rval;
 1120 
 1121         rval = 0;
 1122 
 1123         ch = &sc->sc_record;
 1124         r = CH_READ1(sc, ch, AUVIA_RP_STAT);
 1125         if (r & AUVIA_RPSTAT_INTR) {
 1126                 if (sc->sc_record.sc_intr)
 1127                         sc->sc_record.sc_intr(sc->sc_record.sc_arg);
 1128 
 1129                 /* clear interrupts */
 1130                 CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
 1131                 rval = 1;
 1132         }
 1133 
 1134         ch = &sc->sc_play;
 1135         r = CH_READ1(sc, ch, AUVIA_RP_STAT);
 1136         if (r & AUVIA_RPSTAT_INTR) {
 1137                 if (sc->sc_play.sc_intr)
 1138                         sc->sc_play.sc_intr(sc->sc_play.sc_arg);
 1139 
 1140                 /* clear interrupts */
 1141                 CH_WRITE1(sc, ch, AUVIA_RP_STAT, AUVIA_RPSTAT_INTR);
 1142                 rval = 1;
 1143         }
 1144 
 1145         return rval;
 1146 }

Cache object: e5cec3bbb91a106098d91f973029e40e


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