root/dev/pci/auvia.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. auvia_match
  2. auvia_attach
  3. auvia_attach_codec
  4. auvia_reset_codec
  5. auvia_waitready_codec
  6. auvia_waitvalid_codec
  7. auvia_write_codec
  8. auvia_read_codec
  9. auvia_open
  10. auvia_close
  11. auvia_query_encoding
  12. auvia_set_params
  13. auvia_round_blocksize
  14. auvia_halt_output
  15. auvia_halt_input
  16. auvia_getdev
  17. auvia_set_port
  18. auvia_get_port
  19. auvia_query_devinfo
  20. auvia_malloc
  21. auvia_free
  22. auvia_mappage
  23. auvia_get_props
  24. auvia_build_dma_ops
  25. auvia_trigger_output
  26. auvia_trigger_input
  27. auvia_intr

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

/* [<][>][^][v][top][bottom][index][help] */