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/pci/via8233.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 (c) 2002 Orion Hodson <orion@freebsd.org>
    5  * Portions of this code derived from via82c686.c:
    6  *      Copyright (c) 2000 David Jones <dej@ox.org>
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /*
   32  * Credits due to:
   33  *
   34  * Grzybowski Rafal, Russell Davies, Mark Handley, Daniel O'Connor for
   35  * comments, machine time, testing patches, and patience.  VIA for
   36  * providing specs.  ALSA for helpful comments and some register poke
   37  * ordering.
   38  */
   39 
   40 #ifdef HAVE_KERNEL_OPTION_HEADERS
   41 #include "opt_snd.h"
   42 #endif
   43 
   44 #include <dev/sound/pcm/sound.h>
   45 #include <dev/sound/pcm/ac97.h>
   46 
   47 #include <dev/pci/pcireg.h>
   48 #include <dev/pci/pcivar.h>
   49 #include <sys/sysctl.h>
   50 
   51 #include <dev/sound/pci/via8233.h>
   52 
   53 SND_DECLARE_FILE("$FreeBSD$");
   54 
   55 #define VIA8233_PCI_ID 0x30591106
   56 
   57 #define VIA8233_REV_ID_8233PRE  0x10
   58 #define VIA8233_REV_ID_8233C    0x20
   59 #define VIA8233_REV_ID_8233     0x30
   60 #define VIA8233_REV_ID_8233A    0x40
   61 #define VIA8233_REV_ID_8235     0x50
   62 #define VIA8233_REV_ID_8237     0x60
   63 #define VIA8233_REV_ID_8251     0x70
   64 
   65 #define SEGS_PER_CHAN   2                       /* Segments per channel */
   66 #define NDXSCHANS       4                       /* No of DXS channels */
   67 #define NMSGDCHANS      1                       /* No of multichannel SGD */
   68 #define NWRCHANS        1                       /* No of write channels */
   69 #define NCHANS          (NWRCHANS + NDXSCHANS + NMSGDCHANS)
   70 #define NSEGS           NCHANS * SEGS_PER_CHAN  /* Segments in SGD table */
   71 #define VIA_SEGS_MIN            2
   72 #define VIA_SEGS_MAX            64
   73 #define VIA_SEGS_DEFAULT        2
   74 #define VIA_BLK_MIN             32
   75 #define VIA_BLK_ALIGN           (~(VIA_BLK_MIN - 1))
   76 
   77 #define VIA_DEFAULT_BUFSZ       0x1000
   78 
   79 /* we rely on this struct being packed to 64 bits */
   80 struct via_dma_op {
   81         volatile uint32_t ptr;
   82         volatile uint32_t flags;
   83 #define VIA_DMAOP_EOL         0x80000000
   84 #define VIA_DMAOP_FLAG        0x40000000
   85 #define VIA_DMAOP_STOP        0x20000000
   86 #define VIA_DMAOP_COUNT(x)    ((x)&0x00FFFFFF)
   87 };
   88 
   89 struct via_info;
   90 
   91 struct via_chinfo {
   92         struct via_info *parent;
   93         struct pcm_channel *channel;
   94         struct snd_dbuf *buffer;
   95         struct via_dma_op *sgd_table;
   96         bus_addr_t sgd_addr;
   97         int dir, rbase, active;
   98         unsigned int blksz, blkcnt;
   99         unsigned int ptr, prevptr;
  100 };
  101 
  102 struct via_info {
  103         device_t dev;
  104 
  105         bus_space_tag_t st;
  106         bus_space_handle_t sh;
  107         bus_dma_tag_t parent_dmat;
  108         bus_dma_tag_t sgd_dmat;
  109         bus_dmamap_t sgd_dmamap;
  110         bus_addr_t sgd_addr;
  111 
  112         struct resource *reg, *irq;
  113         int regid, irqid;
  114         void *ih;
  115         struct ac97_info *codec;
  116 
  117         unsigned int bufsz, blkcnt;
  118         int dxs_src, dma_eol_wake;
  119 
  120         struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
  121         struct via_chinfo rch[NWRCHANS];
  122         struct via_dma_op *sgd_table;
  123         uint16_t codec_caps;
  124         uint16_t n_dxs_registered;
  125         int play_num, rec_num;
  126         struct mtx *lock;
  127         struct callout poll_timer;
  128         int poll_ticks, polling;
  129 };
  130 
  131 static uint32_t via_fmt[] = {
  132         SND_FORMAT(AFMT_U8, 1, 0),
  133         SND_FORMAT(AFMT_U8, 2, 0),
  134         SND_FORMAT(AFMT_S16_LE, 1, 0),
  135         SND_FORMAT(AFMT_S16_LE, 2, 0),
  136         0
  137 };
  138 
  139 static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
  140 static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
  141 
  142 static __inline int
  143 via_chan_active(struct via_info *via)
  144 {
  145         int i, ret = 0;
  146 
  147         if (via == NULL)
  148                 return (0);
  149 
  150         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++)
  151                 ret += via->pch[i].active;
  152 
  153         for (i = 0; i < NWRCHANS; i++)
  154                 ret += via->rch[i].active;
  155 
  156         return (ret);
  157 }
  158 
  159 static int
  160 sysctl_via8233_spdif_enable(SYSCTL_HANDLER_ARGS)
  161 {
  162         struct via_info *via;
  163         device_t dev;
  164         uint32_t r;
  165         int err, new_en;
  166 
  167         dev = oidp->oid_arg1;
  168         via = pcm_getdevinfo(dev);
  169         snd_mtxlock(via->lock);
  170         r = pci_read_config(dev, VIA_PCI_SPDIF, 1);
  171         snd_mtxunlock(via->lock);
  172         new_en = (r & VIA_SPDIF_EN) ? 1 : 0;
  173         err = sysctl_handle_int(oidp, &new_en, 0, req);
  174 
  175         if (err || req->newptr == NULL)
  176                 return (err);
  177         if (new_en < 0 || new_en > 1)
  178                 return (EINVAL);
  179 
  180         if (new_en)
  181                 r |= VIA_SPDIF_EN;
  182         else
  183                 r &= ~VIA_SPDIF_EN;
  184         snd_mtxlock(via->lock);
  185         pci_write_config(dev, VIA_PCI_SPDIF, r, 1);
  186         snd_mtxunlock(via->lock);
  187 
  188         return (0);
  189 }
  190 
  191 static int
  192 sysctl_via8233_dxs_src(SYSCTL_HANDLER_ARGS)
  193 {
  194         struct via_info *via;
  195         device_t dev;
  196         int err, val;
  197 
  198         dev = oidp->oid_arg1;
  199         via = pcm_getdevinfo(dev);
  200         snd_mtxlock(via->lock);
  201         val = via->dxs_src;
  202         snd_mtxunlock(via->lock);
  203         err = sysctl_handle_int(oidp, &val, 0, req);
  204 
  205         if (err || req->newptr == NULL)
  206                 return (err);
  207         if (val < 0 || val > 1)
  208                 return (EINVAL);
  209 
  210         snd_mtxlock(via->lock);
  211         via->dxs_src = val;
  212         snd_mtxunlock(via->lock);
  213 
  214         return (0);
  215 }
  216 
  217 static int
  218 sysctl_via_polling(SYSCTL_HANDLER_ARGS)
  219 {
  220         struct via_info *via;
  221         device_t dev;
  222         int err, val;
  223 
  224         dev = oidp->oid_arg1;
  225         via = pcm_getdevinfo(dev);
  226         if (via == NULL)
  227                 return (EINVAL);
  228         snd_mtxlock(via->lock);
  229         val = via->polling;
  230         snd_mtxunlock(via->lock);
  231         err = sysctl_handle_int(oidp, &val, 0, req);
  232 
  233         if (err || req->newptr == NULL)
  234                 return (err);
  235         if (val < 0 || val > 1)
  236                 return (EINVAL);
  237 
  238         snd_mtxlock(via->lock);
  239         if (val != via->polling) {
  240                 if (via_chan_active(via) != 0)
  241                         err = EBUSY;
  242                 else if (val == 0)
  243                         via->polling = 0;
  244                 else
  245                         via->polling = 1;
  246         }
  247         snd_mtxunlock(via->lock);
  248 
  249         return (err);
  250 }
  251 
  252 static void
  253 via_init_sysctls(device_t dev)
  254 {
  255         /* XXX: an user should be able to set this with a control tool,
  256            if not done before 7.0-RELEASE, this needs to be converted to
  257            a device specific sysctl "dev.pcm.X.yyy" via device_get_sysctl_*()
  258            as discussed on multimedia@ in msg-id <861wujij2q.fsf@xps.des.no> */
  259         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  260             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
  261             "spdif_enabled", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
  262             dev, sizeof(dev), sysctl_via8233_spdif_enable, "I",
  263             "Enable S/PDIF output on primary playback channel");
  264         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  265             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
  266             "dxs_src", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
  267             dev, sizeof(dev), sysctl_via8233_dxs_src, "I",
  268             "Enable VIA DXS Sample Rate Converter");
  269         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  270             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
  271             "polling", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
  272             dev, sizeof(dev), sysctl_via_polling, "I", "Enable polling mode");
  273 }
  274 
  275 static __inline uint32_t
  276 via_rd(struct via_info *via, int regno, int size)
  277 {
  278         switch (size) {
  279         case 1:
  280                 return (bus_space_read_1(via->st, via->sh, regno));
  281         case 2:
  282                 return (bus_space_read_2(via->st, via->sh, regno));
  283         case 4:
  284                 return (bus_space_read_4(via->st, via->sh, regno));
  285         default:
  286                 return (0xFFFFFFFF);
  287         }
  288 }
  289 
  290 static __inline void
  291 via_wr(struct via_info *via, int regno, uint32_t data, int size)
  292 {
  293 
  294         switch (size) {
  295         case 1:
  296                 bus_space_write_1(via->st, via->sh, regno, data);
  297                 break;
  298         case 2:
  299                 bus_space_write_2(via->st, via->sh, regno, data);
  300                 break;
  301         case 4:
  302                 bus_space_write_4(via->st, via->sh, regno, data);
  303                 break;
  304         }
  305 }
  306 
  307 /* -------------------------------------------------------------------- */
  308 /* Codec interface */
  309 
  310 static int
  311 via_waitready_codec(struct via_info *via)
  312 {
  313         int i;
  314 
  315         /* poll until codec not busy */
  316         for (i = 0; i < 1000; i++) {
  317                 if ((via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_BUSY) == 0)
  318                         return (0);
  319                 DELAY(1);
  320         }
  321         device_printf(via->dev, "%s: codec busy\n", __func__);
  322         return (1);
  323 }
  324 
  325 static int
  326 via_waitvalid_codec(struct via_info *via)
  327 {
  328         int i;
  329 
  330         /* poll until codec valid */
  331         for (i = 0; i < 1000; i++) {
  332                 if (via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_CODEC00_VALID)
  333                         return (0);
  334                 DELAY(1);
  335         }
  336         device_printf(via->dev, "%s: codec invalid\n", __func__);
  337         return (1);
  338 }
  339 
  340 static int
  341 via_write_codec(kobj_t obj, void *addr, int reg, uint32_t val)
  342 {
  343         struct via_info *via = addr;
  344 
  345         if (via_waitready_codec(via))
  346                 return (-1);
  347 
  348         via_wr(via, VIA_AC97_CONTROL,
  349                VIA_AC97_CODEC00_VALID | VIA_AC97_INDEX(reg) |
  350                VIA_AC97_DATA(val), 4);
  351 
  352         return (0);
  353 }
  354 
  355 static int
  356 via_read_codec(kobj_t obj, void *addr, int reg)
  357 {
  358         struct via_info *via = addr;
  359 
  360         if (via_waitready_codec(via))
  361                 return (-1);
  362 
  363         via_wr(via, VIA_AC97_CONTROL, VIA_AC97_CODEC00_VALID |
  364             VIA_AC97_READ | VIA_AC97_INDEX(reg), 4);
  365 
  366         if (via_waitready_codec(via))
  367                 return (-1);
  368 
  369         if (via_waitvalid_codec(via))
  370                 return (-1);
  371 
  372         return (via_rd(via, VIA_AC97_CONTROL, 2));
  373 }
  374 
  375 static kobj_method_t via_ac97_methods[] = {
  376         KOBJMETHOD(ac97_read,           via_read_codec),
  377         KOBJMETHOD(ac97_write,          via_write_codec),
  378         KOBJMETHOD_END
  379 };
  380 AC97_DECLARE(via_ac97);
  381 
  382 /* -------------------------------------------------------------------- */
  383 
  384 static int
  385 via_buildsgdt(struct via_chinfo *ch)
  386 {
  387         uint32_t phys_addr, flag;
  388         int i;
  389 
  390         phys_addr = sndbuf_getbufaddr(ch->buffer);
  391 
  392         for (i = 0; i < ch->blkcnt; i++) {
  393                 flag = (i == ch->blkcnt - 1) ? VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
  394                 ch->sgd_table[i].ptr = phys_addr + (i * ch->blksz);
  395                 ch->sgd_table[i].flags = flag | ch->blksz;
  396         }
  397 
  398         return (0);
  399 }
  400 
  401 /* -------------------------------------------------------------------- */
  402 /* Format setting functions */
  403 
  404 static int
  405 via8233wr_setformat(kobj_t obj, void *data, uint32_t format)
  406 {
  407         struct via_chinfo *ch = data;
  408         struct via_info *via = ch->parent;
  409 
  410         uint32_t f = WR_FORMAT_STOP_INDEX;
  411 
  412         if (AFMT_CHANNEL(format) > 1)
  413                 f |= WR_FORMAT_STEREO;
  414         if (format & AFMT_S16_LE)
  415                 f |= WR_FORMAT_16BIT;
  416         snd_mtxlock(via->lock);
  417         via_wr(via, VIA_WR0_FORMAT, f, 4);
  418         snd_mtxunlock(via->lock);
  419 
  420         return (0);
  421 }
  422 
  423 static int
  424 via8233dxs_setformat(kobj_t obj, void *data, uint32_t format)
  425 {
  426         struct via_chinfo *ch = data;
  427         struct via_info *via = ch->parent;
  428         uint32_t r, v;
  429 
  430         r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
  431         snd_mtxlock(via->lock);
  432         v = via_rd(via, r, 4);
  433 
  434         v &= ~(VIA8233_DXS_RATEFMT_STEREO | VIA8233_DXS_RATEFMT_16BIT);
  435         if (AFMT_CHANNEL(format) > 1)
  436                 v |= VIA8233_DXS_RATEFMT_STEREO;
  437         if (format & AFMT_16BIT)
  438                 v |= VIA8233_DXS_RATEFMT_16BIT;
  439         via_wr(via, r, v, 4);
  440         snd_mtxunlock(via->lock);
  441 
  442         return (0);
  443 }
  444 
  445 static int
  446 via8233msgd_setformat(kobj_t obj, void *data, uint32_t format)
  447 {
  448         struct via_chinfo *ch = data;
  449         struct via_info *via = ch->parent;
  450 
  451         uint32_t s = 0xff000000;
  452         uint8_t  v = (format & AFMT_S16_LE) ? MC_SGD_16BIT : MC_SGD_8BIT;
  453 
  454         if (AFMT_CHANNEL(format) > 1) {
  455                 v |= MC_SGD_CHANNELS(2);
  456                 s |= SLOT3(1) | SLOT4(2);
  457         } else {
  458                 v |= MC_SGD_CHANNELS(1);
  459                 s |= SLOT3(1) | SLOT4(1);
  460         }
  461 
  462         snd_mtxlock(via->lock);
  463         via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
  464         via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
  465         snd_mtxunlock(via->lock);
  466 
  467         return (0);
  468 }
  469 
  470 /* -------------------------------------------------------------------- */
  471 /* Speed setting functions */
  472 
  473 static uint32_t
  474 via8233wr_setspeed(kobj_t obj, void *data, uint32_t speed)
  475 {
  476         struct via_chinfo *ch = data;
  477         struct via_info *via = ch->parent;
  478 
  479         if (via->codec_caps & AC97_EXTCAP_VRA)
  480                 return (ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed));
  481 
  482         return (48000);
  483 }
  484 
  485 static uint32_t
  486 via8233dxs_setspeed(kobj_t obj, void *data, uint32_t speed)
  487 {
  488         struct via_chinfo *ch = data;
  489         struct via_info *via = ch->parent;
  490         uint32_t r, v;
  491 
  492         r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
  493         snd_mtxlock(via->lock);
  494         v = via_rd(via, r, 4) & ~VIA8233_DXS_RATEFMT_48K;
  495 
  496         /* Careful to avoid overflow (divide by 48 per vt8233c docs) */
  497 
  498         v |= VIA8233_DXS_RATEFMT_48K * (speed / 48) / (48000 / 48);
  499         via_wr(via, r, v, 4);
  500         snd_mtxunlock(via->lock);
  501 
  502         return (speed);
  503 }
  504 
  505 static uint32_t
  506 via8233msgd_setspeed(kobj_t obj, void *data, uint32_t speed)
  507 {
  508         struct via_chinfo *ch = data;
  509         struct via_info *via = ch->parent;
  510 
  511         if (via->codec_caps & AC97_EXTCAP_VRA)
  512                 return (ac97_setrate(via->codec, AC97_REGEXT_FDACRATE, speed));
  513 
  514         return (48000);
  515 }
  516 
  517 /* -------------------------------------------------------------------- */
  518 /* Format probing functions */
  519 
  520 static struct pcmchan_caps *
  521 via8233wr_getcaps(kobj_t obj, void *data)
  522 {
  523         struct via_chinfo *ch = data;
  524         struct via_info *via = ch->parent;
  525 
  526         /* Controlled by ac97 registers */
  527         if (via->codec_caps & AC97_EXTCAP_VRA)
  528                 return (&via_vracaps);
  529         return (&via_caps);
  530 }
  531 
  532 static struct pcmchan_caps *
  533 via8233dxs_getcaps(kobj_t obj, void *data)
  534 {
  535         struct via_chinfo *ch = data;
  536         struct via_info *via = ch->parent;
  537 
  538         /*
  539          * Controlled by onboard registers
  540          *
  541          * Apparently, few boards can do DXS sample rate
  542          * conversion.
  543          */
  544         if (via->dxs_src)
  545                 return (&via_vracaps);
  546         return (&via_caps);
  547 }
  548 
  549 static struct pcmchan_caps *
  550 via8233msgd_getcaps(kobj_t obj, void *data)
  551 {
  552         struct via_chinfo *ch = data;
  553         struct via_info *via = ch->parent;
  554 
  555         /* Controlled by ac97 registers */
  556         if (via->codec_caps & AC97_EXTCAP_VRA)
  557                 return (&via_vracaps);
  558         return (&via_caps);
  559 }
  560 
  561 /* -------------------------------------------------------------------- */
  562 /* Common functions */
  563 
  564 static int
  565 via8233chan_setfragments(kobj_t obj, void *data,
  566                                         uint32_t blksz, uint32_t blkcnt)
  567 {
  568         struct via_chinfo *ch = data;
  569         struct via_info *via = ch->parent;
  570 
  571         blksz &= VIA_BLK_ALIGN;
  572 
  573         if (blksz > (sndbuf_getmaxsize(ch->buffer) / VIA_SEGS_MIN))
  574                 blksz = sndbuf_getmaxsize(ch->buffer) / VIA_SEGS_MIN;
  575         if (blksz < VIA_BLK_MIN)
  576                 blksz = VIA_BLK_MIN;
  577         if (blkcnt > VIA_SEGS_MAX)
  578                 blkcnt = VIA_SEGS_MAX;
  579         if (blkcnt < VIA_SEGS_MIN)
  580                 blkcnt = VIA_SEGS_MIN;
  581 
  582         while ((blksz * blkcnt) > sndbuf_getmaxsize(ch->buffer)) {
  583                 if ((blkcnt >> 1) >= VIA_SEGS_MIN)
  584                         blkcnt >>= 1;
  585                 else if ((blksz >> 1) >= VIA_BLK_MIN)
  586                         blksz >>= 1;
  587                 else
  588                         break;
  589         }
  590 
  591         if ((sndbuf_getblksz(ch->buffer) != blksz ||
  592             sndbuf_getblkcnt(ch->buffer) != blkcnt) &&
  593             sndbuf_resize(ch->buffer, blkcnt, blksz) != 0)
  594                 device_printf(via->dev, "%s: failed blksz=%u blkcnt=%u\n",
  595                     __func__, blksz, blkcnt);
  596 
  597         ch->blksz = sndbuf_getblksz(ch->buffer);
  598         ch->blkcnt = sndbuf_getblkcnt(ch->buffer);
  599 
  600         return (0);
  601 }
  602 
  603 static uint32_t
  604 via8233chan_setblocksize(kobj_t obj, void *data, uint32_t blksz)
  605 {
  606         struct via_chinfo *ch = data;
  607         struct via_info *via = ch->parent;
  608 
  609         via8233chan_setfragments(obj, data, blksz, via->blkcnt);
  610 
  611         return (ch->blksz);
  612 }
  613 
  614 static uint32_t
  615 via8233chan_getptr(kobj_t obj, void *data)
  616 {
  617         struct via_chinfo *ch = data;
  618         struct via_info *via = ch->parent;
  619         uint32_t v, index, count, ptr;
  620 
  621         snd_mtxlock(via->lock);
  622         if (via->polling != 0) {
  623                 ptr = ch->ptr;
  624                 snd_mtxunlock(via->lock);
  625         } else {
  626                 v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
  627                 snd_mtxunlock(via->lock);
  628                 index = v >> 24;                /* Last completed buffer */
  629                 count = v & 0x00ffffff; /* Bytes remaining */
  630                 ptr = (index + 1) * ch->blksz - count;
  631                 ptr %= ch->blkcnt * ch->blksz;  /* Wrap to available space */
  632         }
  633 
  634         return (ptr);
  635 }
  636 
  637 static void
  638 via8233chan_reset(struct via_info *via, struct via_chinfo *ch)
  639 {
  640         via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
  641         via_wr(via, ch->rbase + VIA_RP_CONTROL, 0x00, 1);
  642         via_wr(via, ch->rbase + VIA_RP_STATUS,
  643             SGD_STATUS_EOL | SGD_STATUS_FLAG, 1);
  644 }
  645 
  646 /* -------------------------------------------------------------------- */
  647 /* Channel initialization functions */
  648 
  649 static void
  650 via8233chan_sgdinit(struct via_info *via, struct via_chinfo *ch, int chnum)
  651 {
  652         ch->sgd_table = &via->sgd_table[chnum * VIA_SEGS_MAX];
  653         ch->sgd_addr = via->sgd_addr + chnum * VIA_SEGS_MAX *
  654             sizeof(struct via_dma_op);
  655 }
  656 
  657 static void*
  658 via8233wr_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  659                                                 struct pcm_channel *c, int dir)
  660 {
  661         struct via_info *via = devinfo;
  662         struct via_chinfo *ch;
  663         int num;
  664 
  665         snd_mtxlock(via->lock);
  666         num = via->rec_num++;
  667         ch = &via->rch[num];
  668         ch->parent = via;
  669         ch->channel = c;
  670         ch->buffer = b;
  671         ch->dir = dir;
  672         ch->blkcnt = via->blkcnt;
  673         ch->rbase = VIA_WR_BASE(num);
  674         via_wr(via, ch->rbase + VIA_WR_RP_SGD_FORMAT, WR_FIFO_ENABLE, 1);
  675         snd_mtxunlock(via->lock);
  676 
  677         if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0)
  678                 return (NULL);
  679 
  680         snd_mtxlock(via->lock);
  681         via8233chan_sgdinit(via, ch, num);
  682         via8233chan_reset(via, ch);
  683         snd_mtxunlock(via->lock);
  684 
  685         return (ch);
  686 }
  687 
  688 static void*
  689 via8233dxs_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  690                                                 struct pcm_channel *c, int dir)
  691 {
  692         struct via_info *via = devinfo;
  693         struct via_chinfo *ch;
  694         int num;
  695 
  696         snd_mtxlock(via->lock);
  697         num = via->play_num++;
  698         ch = &via->pch[num];
  699         ch->parent = via;
  700         ch->channel = c;
  701         ch->buffer = b;
  702         ch->dir = dir;
  703         ch->blkcnt = via->blkcnt;
  704 
  705         /*
  706          * All cards apparently support DXS3, but not other DXS
  707          * channels.  We therefore want to align first DXS channel to
  708          * DXS3.
  709          */
  710         ch->rbase = VIA_DXS_BASE(NDXSCHANS - 1 - via->n_dxs_registered);
  711         via->n_dxs_registered++;
  712         snd_mtxunlock(via->lock);
  713 
  714         if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0)
  715                 return (NULL);
  716 
  717         snd_mtxlock(via->lock);
  718         via8233chan_sgdinit(via, ch, NWRCHANS + num);
  719         via8233chan_reset(via, ch);
  720         snd_mtxunlock(via->lock);
  721 
  722         return (ch);
  723 }
  724 
  725 static void*
  726 via8233msgd_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  727                                                 struct pcm_channel *c, int dir)
  728 {
  729         struct via_info *via = devinfo;
  730         struct via_chinfo *ch;
  731         int num;
  732 
  733         snd_mtxlock(via->lock);
  734         num = via->play_num++;
  735         ch = &via->pch[num];
  736         ch->parent = via;
  737         ch->channel = c;
  738         ch->buffer = b;
  739         ch->dir = dir;
  740         ch->rbase = VIA_MC_SGD_STATUS;
  741         ch->blkcnt = via->blkcnt;
  742         snd_mtxunlock(via->lock);
  743 
  744         if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0)
  745                 return (NULL);
  746 
  747         snd_mtxlock(via->lock);
  748         via8233chan_sgdinit(via, ch, NWRCHANS + num);
  749         via8233chan_reset(via, ch);
  750         snd_mtxunlock(via->lock);
  751 
  752         return (ch);
  753 }
  754 
  755 static void
  756 via8233chan_mute(struct via_info *via, struct via_chinfo *ch, int muted)
  757 {
  758         if (BASE_IS_VIA_DXS_REG(ch->rbase)) {
  759                 int r;
  760                 muted = (muted) ? VIA8233_DXS_MUTE : 0;
  761                 via_wr(via, ch->rbase + VIA8233_RP_DXS_LVOL, muted, 1);
  762                 via_wr(via, ch->rbase + VIA8233_RP_DXS_RVOL, muted, 1);
  763                 r = via_rd(via, ch->rbase + VIA8233_RP_DXS_LVOL, 1) &
  764                     VIA8233_DXS_MUTE;
  765                 if (r != muted)
  766                         device_printf(via->dev,
  767                             "%s: failed to set dxs volume "
  768                             "(dxs base 0x%02x).\n", __func__, ch->rbase);
  769         }
  770 }
  771 
  772 static __inline int
  773 via_poll_channel(struct via_chinfo *ch)
  774 {
  775         struct via_info *via;
  776         uint32_t sz, delta;
  777         uint32_t v, index, count;
  778         int ptr;
  779 
  780         if (ch == NULL || ch->channel == NULL || ch->active == 0)
  781                 return (0);
  782 
  783         via = ch->parent;
  784         sz = ch->blksz * ch->blkcnt;
  785         v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
  786         index = v >> 24;
  787         count = v & 0x00ffffff;
  788         ptr = ((index + 1) * ch->blksz) - count;
  789         ptr %= sz;
  790         ptr &= ~(ch->blksz - 1);
  791         ch->ptr = ptr;
  792         delta = (sz + ptr - ch->prevptr) % sz;
  793 
  794         if (delta < ch->blksz)
  795                 return (0);
  796 
  797         ch->prevptr = ptr;
  798 
  799         return (1);
  800 }
  801 
  802 static void
  803 via_poll_callback(void *arg)
  804 {
  805         struct via_info *via = arg;
  806         uint32_t ptrigger = 0, rtrigger = 0;
  807         int i;
  808 
  809         if (via == NULL)
  810                 return;
  811 
  812         snd_mtxlock(via->lock);
  813         if (via->polling == 0 || via_chan_active(via) == 0) {
  814                 snd_mtxunlock(via->lock);
  815                 return;
  816         }
  817 
  818         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++)
  819                 ptrigger |= (via_poll_channel(&via->pch[i]) != 0) ?
  820                     (1 << i) : 0;
  821 
  822         for (i = 0; i < NWRCHANS; i++)
  823                 rtrigger |= (via_poll_channel(&via->rch[i]) != 0) ?
  824                     (1 << i) : 0;
  825 
  826         /* XXX */
  827         callout_reset(&via->poll_timer, 1/*via->poll_ticks*/,
  828             via_poll_callback, via);
  829 
  830         snd_mtxunlock(via->lock);
  831 
  832         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
  833                 if (ptrigger & (1 << i))
  834                         chn_intr(via->pch[i].channel);
  835         }
  836         for (i = 0; i < NWRCHANS; i++) {
  837                 if (rtrigger & (1 << i))
  838                         chn_intr(via->rch[i].channel);
  839         }
  840 }
  841 
  842 static int
  843 via_poll_ticks(struct via_info *via)
  844 {
  845         struct via_chinfo *ch;
  846         int i;
  847         int ret = hz;
  848         int pollticks;
  849 
  850         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
  851                 ch = &via->pch[i];
  852                 if (ch->channel == NULL || ch->active == 0)
  853                         continue;
  854                 pollticks = ((uint64_t)hz * ch->blksz) /
  855                     ((uint64_t)sndbuf_getalign(ch->buffer) *
  856                     sndbuf_getspd(ch->buffer));
  857                 pollticks >>= 2;
  858                 if (pollticks > hz)
  859                         pollticks = hz;
  860                 if (pollticks < 1)
  861                         pollticks = 1;
  862                 if (pollticks < ret)
  863                         ret = pollticks;
  864         }
  865 
  866         for (i = 0; i < NWRCHANS; i++) {
  867                 ch = &via->rch[i];
  868                 if (ch->channel == NULL || ch->active == 0)
  869                         continue;
  870                 pollticks = ((uint64_t)hz * ch->blksz) /
  871                     ((uint64_t)sndbuf_getalign(ch->buffer) *
  872                     sndbuf_getspd(ch->buffer));
  873                 pollticks >>= 2;
  874                 if (pollticks > hz)
  875                         pollticks = hz;
  876                 if (pollticks < 1)
  877                         pollticks = 1;
  878                 if (pollticks < ret)
  879                         ret = pollticks;
  880         }
  881 
  882         return (ret);
  883 }
  884 
  885 static int
  886 via8233chan_trigger(kobj_t obj, void* data, int go)
  887 {
  888         struct via_chinfo *ch = data;
  889         struct via_info *via = ch->parent;
  890         int pollticks;
  891 
  892         if (!PCMTRIG_COMMON(go))
  893                 return (0);
  894 
  895         snd_mtxlock(via->lock);
  896         switch(go) {
  897         case PCMTRIG_START:
  898                 via_buildsgdt(ch);
  899                 via8233chan_mute(via, ch, 0);
  900                 via_wr(via, ch->rbase + VIA_RP_TABLE_PTR, ch->sgd_addr, 4);
  901                 if (via->polling != 0) {
  902                         ch->ptr = 0;
  903                         ch->prevptr = 0;
  904                         pollticks = ((uint64_t)hz * ch->blksz) /
  905                             ((uint64_t)sndbuf_getalign(ch->buffer) *
  906                             sndbuf_getspd(ch->buffer));
  907                         pollticks >>= 2;
  908                         if (pollticks > hz)
  909                                 pollticks = hz;
  910                         if (pollticks < 1)
  911                                 pollticks = 1;
  912                         if (via_chan_active(via) == 0 ||
  913                             pollticks < via->poll_ticks) {
  914                                 if (bootverbose) {
  915                                         if (via_chan_active(via) == 0)
  916                                                 printf("%s: pollticks=%d\n",
  917                                                     __func__, pollticks);
  918                                         else
  919                                                 printf("%s: "
  920                                                     "pollticks %d -> %d\n",
  921                                                     __func__, via->poll_ticks,
  922                                                     pollticks);
  923                                 }
  924                                 via->poll_ticks = pollticks;
  925                                 callout_reset(&via->poll_timer, 1,
  926                                     via_poll_callback, via);
  927                         }
  928                 }
  929                 via_wr(via, ch->rbase + VIA_RP_CONTROL,
  930                     SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
  931                     ((via->polling == 0) ?
  932                     (SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG) : 0), 1);
  933                 ch->active = 1;
  934                 break;
  935         case PCMTRIG_STOP:
  936         case PCMTRIG_ABORT:
  937                 via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
  938                 via8233chan_mute(via, ch, 1);
  939                 via8233chan_reset(via, ch);
  940                 ch->active = 0;
  941                 if (via->polling != 0) {
  942                         if (via_chan_active(via) == 0) {
  943                                 callout_stop(&via->poll_timer);
  944                                 via->poll_ticks = 1;
  945                         } else {
  946                                 pollticks = via_poll_ticks(via);
  947                                 if (pollticks > via->poll_ticks) {
  948                                         if (bootverbose)
  949                                                 printf("%s: pollticks "
  950                                                     "%d -> %d\n",
  951                                                     __func__, via->poll_ticks,
  952                                                     pollticks);
  953                                         via->poll_ticks = pollticks;
  954                                         callout_reset(&via->poll_timer,
  955                                             1, via_poll_callback,
  956                                             via);
  957                                 }
  958                         }
  959                 }
  960                 break;
  961         default:
  962                 break;
  963         }
  964         snd_mtxunlock(via->lock);
  965         return (0);
  966 }
  967 
  968 static kobj_method_t via8233wr_methods[] = {
  969         KOBJMETHOD(channel_init,                via8233wr_init),
  970         KOBJMETHOD(channel_setformat,           via8233wr_setformat),
  971         KOBJMETHOD(channel_setspeed,            via8233wr_setspeed),
  972         KOBJMETHOD(channel_getcaps,             via8233wr_getcaps),
  973         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
  974         KOBJMETHOD(channel_setfragments,        via8233chan_setfragments),
  975         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
  976         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
  977         KOBJMETHOD_END
  978 };
  979 CHANNEL_DECLARE(via8233wr);
  980 
  981 static kobj_method_t via8233dxs_methods[] = {
  982         KOBJMETHOD(channel_init,                via8233dxs_init),
  983         KOBJMETHOD(channel_setformat,           via8233dxs_setformat),
  984         KOBJMETHOD(channel_setspeed,            via8233dxs_setspeed),
  985         KOBJMETHOD(channel_getcaps,             via8233dxs_getcaps),
  986         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
  987         KOBJMETHOD(channel_setfragments,        via8233chan_setfragments),
  988         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
  989         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
  990         KOBJMETHOD_END
  991 };
  992 CHANNEL_DECLARE(via8233dxs);
  993 
  994 static kobj_method_t via8233msgd_methods[] = {
  995         KOBJMETHOD(channel_init,                via8233msgd_init),
  996         KOBJMETHOD(channel_setformat,           via8233msgd_setformat),
  997         KOBJMETHOD(channel_setspeed,            via8233msgd_setspeed),
  998         KOBJMETHOD(channel_getcaps,             via8233msgd_getcaps),
  999         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
 1000         KOBJMETHOD(channel_setfragments,        via8233chan_setfragments),
 1001         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
 1002         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
 1003         KOBJMETHOD_END
 1004 };
 1005 CHANNEL_DECLARE(via8233msgd);
 1006 
 1007 /* -------------------------------------------------------------------- */
 1008 
 1009 static void
 1010 via_intr(void *p)
 1011 {
 1012         struct via_info *via = p;
 1013         uint32_t ptrigger = 0, rtrigger = 0;
 1014         int i, reg, stat;
 1015 
 1016         snd_mtxlock(via->lock);
 1017         if (via->polling != 0) {
 1018                 snd_mtxunlock(via->lock);
 1019                 return;
 1020         }
 1021         /* Poll playback channels */
 1022         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
 1023                 if (via->pch[i].channel == NULL || via->pch[i].active == 0)
 1024                         continue;
 1025                 reg = via->pch[i].rbase + VIA_RP_STATUS;
 1026                 stat = via_rd(via, reg, 1);
 1027                 if (stat & SGD_STATUS_INTR) {
 1028                         if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
 1029                             !(stat & SGD_STATUS_ACTIVE)))
 1030                                 via_wr(via, via->pch[i].rbase + VIA_RP_CONTROL,
 1031                                     SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
 1032                                     SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1);
 1033                         via_wr(via, reg, stat, 1);
 1034                         ptrigger |= 1 << i;
 1035                 }
 1036         }
 1037         /* Poll record channels */
 1038         for (i = 0; i < NWRCHANS; i++) {
 1039                 if (via->rch[i].channel == NULL || via->rch[i].active == 0)
 1040                         continue;
 1041                 reg = via->rch[i].rbase + VIA_RP_STATUS;
 1042                 stat = via_rd(via, reg, 1);
 1043                 if (stat & SGD_STATUS_INTR) {
 1044                         if (via->dma_eol_wake && ((stat & SGD_STATUS_EOL) ||
 1045                             !(stat & SGD_STATUS_ACTIVE)))
 1046                                 via_wr(via, via->rch[i].rbase + VIA_RP_CONTROL,
 1047                                     SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
 1048                                     SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1);
 1049                         via_wr(via, reg, stat, 1);
 1050                         rtrigger |= 1 << i;
 1051                 }
 1052         }
 1053         snd_mtxunlock(via->lock);
 1054 
 1055         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
 1056                 if (ptrigger & (1 << i))
 1057                         chn_intr(via->pch[i].channel);
 1058         }
 1059         for (i = 0; i < NWRCHANS; i++) {
 1060                 if (rtrigger & (1 << i))
 1061                         chn_intr(via->rch[i].channel);
 1062         }
 1063 }
 1064 
 1065 /*
 1066  *  Probe and attach the card
 1067  */
 1068 static int
 1069 via_probe(device_t dev)
 1070 {
 1071         switch(pci_get_devid(dev)) {
 1072         case VIA8233_PCI_ID:
 1073                 switch(pci_get_revid(dev)) {
 1074                 case VIA8233_REV_ID_8233PRE:
 1075                         device_set_desc(dev, "VIA VT8233 (pre)");
 1076                         return (BUS_PROBE_DEFAULT);
 1077                 case VIA8233_REV_ID_8233C:
 1078                         device_set_desc(dev, "VIA VT8233C");
 1079                         return (BUS_PROBE_DEFAULT);
 1080                 case VIA8233_REV_ID_8233:
 1081                         device_set_desc(dev, "VIA VT8233");
 1082                         return (BUS_PROBE_DEFAULT);
 1083                 case VIA8233_REV_ID_8233A:
 1084                         device_set_desc(dev, "VIA VT8233A");
 1085                         return (BUS_PROBE_DEFAULT);
 1086                 case VIA8233_REV_ID_8235:
 1087                         device_set_desc(dev, "VIA VT8235");
 1088                         return (BUS_PROBE_DEFAULT);
 1089                 case VIA8233_REV_ID_8237:
 1090                         device_set_desc(dev, "VIA VT8237");
 1091                         return (BUS_PROBE_DEFAULT);
 1092                 case VIA8233_REV_ID_8251:
 1093                         device_set_desc(dev, "VIA VT8251");
 1094                         return (BUS_PROBE_DEFAULT);
 1095                 default:
 1096                         device_set_desc(dev, "VIA VT8233X");    /* Unknown */
 1097                         return (BUS_PROBE_DEFAULT);
 1098                 }
 1099         }
 1100         return (ENXIO);
 1101 }
 1102 
 1103 static void
 1104 dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
 1105 {
 1106         struct via_info *via = (struct via_info *)p;
 1107         via->sgd_addr = bds->ds_addr;
 1108 }
 1109 
 1110 static int
 1111 via_chip_init(device_t dev)
 1112 {
 1113         uint32_t data, cnt;
 1114 
 1115         /* Wake up and reset AC97 if necessary */
 1116         data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
 1117 
 1118         if ((data & VIA_PCI_ACLINK_C00_READY) == 0) {
 1119                 /* Cold reset per ac97r2.3 spec (page 95) */
 1120                 /* Assert low */
 1121                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
 1122                     VIA_PCI_ACLINK_EN, 1);
 1123                 /* Wait T_rst_low */
 1124                 DELAY(100);
 1125                 /* Assert high */
 1126                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
 1127                     VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST, 1);
 1128                 /* Wait T_rst2clk */
 1129                 DELAY(5);
 1130                 /* Assert low */
 1131                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
 1132                     VIA_PCI_ACLINK_EN, 1);
 1133         } else {
 1134                 /* Warm reset */
 1135                 /* Force no sync */
 1136                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
 1137                     VIA_PCI_ACLINK_EN, 1);
 1138                 DELAY(100);
 1139                 /* Sync */
 1140                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
 1141                     VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_SYNC, 1);
 1142                 /* Wait T_sync_high */
 1143                 DELAY(5);
 1144                 /* Force no sync */
 1145                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL,
 1146                     VIA_PCI_ACLINK_EN, 1);
 1147                 /* Wait T_sync2clk */
 1148                 DELAY(5);
 1149         }
 1150 
 1151         /* Power everything up */
 1152         pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_DESIRED, 1);
 1153 
 1154         /* Wait for codec to become ready (largest reported delay 310ms) */
 1155         for (cnt = 0; cnt < 2000; cnt++) {
 1156                 data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
 1157                 if (data & VIA_PCI_ACLINK_C00_READY)
 1158                         return (0);
 1159                 DELAY(5000);
 1160         }
 1161         device_printf(dev, "primary codec not ready (cnt = 0x%02x)\n", cnt);
 1162         return (ENXIO);
 1163 }
 1164 
 1165 static int
 1166 via_attach(device_t dev)
 1167 {
 1168         struct via_info *via = NULL;
 1169         char status[SND_STATUSLEN];
 1170         int i, via_dxs_disabled, via_dxs_src, via_dxs_chnum, via_sgd_chnum;
 1171         int nsegs;
 1172         uint32_t revid;
 1173 
 1174         via = malloc(sizeof *via, M_DEVBUF, M_WAITOK | M_ZERO);
 1175         via->lock = snd_mtxcreate(device_get_nameunit(dev),
 1176             "snd_via8233 softc");
 1177         via->dev = dev;
 1178 
 1179         callout_init(&via->poll_timer, 1);
 1180         via->poll_ticks = 1;
 1181 
 1182         if (resource_int_value(device_get_name(dev),
 1183             device_get_unit(dev), "polling", &i) == 0 && i != 0)
 1184                 via->polling = 1;
 1185         else
 1186                 via->polling = 0;
 1187 
 1188         pci_set_powerstate(dev, PCI_POWERSTATE_D0);
 1189         pci_enable_busmaster(dev);
 1190 
 1191         via->regid = PCIR_BAR(0);
 1192         via->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &via->regid,
 1193                                           RF_ACTIVE);
 1194         if (!via->reg) {
 1195                 device_printf(dev, "cannot allocate bus resource.");
 1196                 goto bad;
 1197         }
 1198         via->st = rman_get_bustag(via->reg);
 1199         via->sh = rman_get_bushandle(via->reg);
 1200 
 1201         via->irqid = 0;
 1202         via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
 1203             RF_ACTIVE | RF_SHAREABLE);
 1204         if (!via->irq ||
 1205             snd_setup_intr(dev, via->irq, INTR_MPSAFE,
 1206             via_intr, via, &via->ih)) {
 1207                 device_printf(dev, "unable to map interrupt\n");
 1208                 goto bad;
 1209         }
 1210 
 1211         via->bufsz = pcm_getbuffersize(dev, 4096, VIA_DEFAULT_BUFSZ, 65536);
 1212         if (resource_int_value(device_get_name(dev),
 1213             device_get_unit(dev), "blocksize", &i) == 0 && i > 0) {
 1214                 i &= VIA_BLK_ALIGN;
 1215                 if (i < VIA_BLK_MIN)
 1216                         i = VIA_BLK_MIN;
 1217                 via->blkcnt = via->bufsz / i;
 1218                 i = 0;
 1219                 while (via->blkcnt >> i)
 1220                         i++;
 1221                 via->blkcnt = 1 << (i - 1);
 1222                 if (via->blkcnt < VIA_SEGS_MIN)
 1223                         via->blkcnt = VIA_SEGS_MIN;
 1224                 else if (via->blkcnt > VIA_SEGS_MAX)
 1225                         via->blkcnt = VIA_SEGS_MAX;
 1226 
 1227         } else
 1228                 via->blkcnt = VIA_SEGS_DEFAULT;
 1229 
 1230         revid = pci_get_revid(dev);
 1231 
 1232         /*
 1233          * VIA8251 lost its interrupt after DMA EOL, and need
 1234          * a gentle spank on its face within interrupt handler.
 1235          */
 1236         if (revid == VIA8233_REV_ID_8251)
 1237                 via->dma_eol_wake = 1;
 1238         else
 1239                 via->dma_eol_wake = 0;
 1240 
 1241         /*
 1242          * Decide whether DXS had to be disabled or not
 1243          */
 1244         if (revid == VIA8233_REV_ID_8233A) {
 1245                 /*
 1246                  * DXS channel is disabled.  Reports from multiple users
 1247                  * that it plays at half-speed.  Do not see this behaviour
 1248                  * on available 8233C or when emulating 8233A register set
 1249                  * on 8233C (either with or without ac97 VRA).
 1250                  */
 1251                 via_dxs_disabled = 1;
 1252         } else if (resource_int_value(device_get_name(dev),
 1253             device_get_unit(dev), "via_dxs_disabled",
 1254             &via_dxs_disabled) == 0)
 1255                 via_dxs_disabled = (via_dxs_disabled > 0) ? 1 : 0;
 1256         else
 1257                 via_dxs_disabled = 0;
 1258 
 1259         if (via_dxs_disabled) {
 1260                 via_dxs_chnum = 0;
 1261                 via_sgd_chnum = 1;
 1262         } else {
 1263                 if (resource_int_value(device_get_name(dev),
 1264                     device_get_unit(dev), "via_dxs_channels",
 1265                     &via_dxs_chnum) != 0)
 1266                         via_dxs_chnum = NDXSCHANS;
 1267                 if (resource_int_value(device_get_name(dev),
 1268                     device_get_unit(dev), "via_sgd_channels",
 1269                     &via_sgd_chnum) != 0)
 1270                         via_sgd_chnum = NMSGDCHANS;
 1271         }
 1272         if (via_dxs_chnum > NDXSCHANS)
 1273                 via_dxs_chnum = NDXSCHANS;
 1274         else if (via_dxs_chnum < 0)
 1275                 via_dxs_chnum = 0;
 1276         if (via_sgd_chnum > NMSGDCHANS)
 1277                 via_sgd_chnum = NMSGDCHANS;
 1278         else if (via_sgd_chnum < 0)
 1279                 via_sgd_chnum = 0;
 1280         if (via_dxs_chnum + via_sgd_chnum < 1) {
 1281                 /* Minimalist ? */
 1282                 via_dxs_chnum = 1;
 1283                 via_sgd_chnum = 0;
 1284         }
 1285         if (via_dxs_chnum > 0 && resource_int_value(device_get_name(dev),
 1286             device_get_unit(dev), "via_dxs_src", &via_dxs_src) == 0)
 1287                 via->dxs_src = (via_dxs_src > 0) ? 1 : 0;
 1288         else
 1289                 via->dxs_src = 0;
 1290 
 1291         nsegs = (via_dxs_chnum + via_sgd_chnum + NWRCHANS) * VIA_SEGS_MAX;
 1292 
 1293         /* DMA tag for buffers */
 1294         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
 1295                 /*boundary*/0,
 1296                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
 1297                 /*highaddr*/BUS_SPACE_MAXADDR,
 1298                 /*filter*/NULL, /*filterarg*/NULL,
 1299                 /*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
 1300                 /*flags*/0, /*lockfunc*/NULL,
 1301                 /*lockarg*/NULL, &via->parent_dmat) != 0) {
 1302                 device_printf(dev, "unable to create dma tag\n");
 1303                 goto bad;
 1304         }
 1305 
 1306         /*
 1307          *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
 1308          *  requires a list in memory of work to do.  We need only 16 bytes
 1309          *  for this list, and it is wasteful to allocate 16K.
 1310          */
 1311         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
 1312                 /*boundary*/0,
 1313                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
 1314                 /*highaddr*/BUS_SPACE_MAXADDR,
 1315                 /*filter*/NULL, /*filterarg*/NULL,
 1316                 /*maxsize*/nsegs * sizeof(struct via_dma_op),
 1317                 /*nsegments*/1, /*maxsegz*/0x3ffff,
 1318                 /*flags*/0, /*lockfunc*/NULL,
 1319                 /*lockarg*/NULL, &via->sgd_dmat) != 0) {
 1320                 device_printf(dev, "unable to create dma tag\n");
 1321                 goto bad;
 1322         }
 1323 
 1324         if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
 1325             BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1)
 1326                 goto bad;
 1327         if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table,
 1328             nsegs * sizeof(struct via_dma_op), dma_cb, via, 0))
 1329                 goto bad;
 1330 
 1331         if (via_chip_init(dev))
 1332                 goto bad;
 1333 
 1334         via->codec = AC97_CREATE(dev, via, via_ac97);
 1335         if (!via->codec)
 1336                 goto bad;
 1337 
 1338         mixer_init(dev, ac97_getmixerclass(), via->codec);
 1339 
 1340         via->codec_caps = ac97_getextcaps(via->codec);
 1341 
 1342         /* Try to set VRA without generating an error, VRM not reqrd yet */
 1343         if (via->codec_caps &
 1344             (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM | AC97_EXTCAP_DRA)) {
 1345                 uint16_t ext = ac97_getextmode(via->codec);
 1346                 ext |= (via->codec_caps &
 1347                     (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM));
 1348                 ext &= ~AC97_EXTCAP_DRA;
 1349                 ac97_setextmode(via->codec, ext);
 1350         }
 1351 
 1352         snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
 1353             rman_get_start(via->reg), rman_get_start(via->irq),
 1354             PCM_KLDSTRING(snd_via8233));
 1355 
 1356         /* Register */
 1357         if (pcm_register(dev, via, via_dxs_chnum + via_sgd_chnum, NWRCHANS))
 1358               goto bad;
 1359         for (i = 0; i < via_dxs_chnum; i++)
 1360               pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
 1361         for (i = 0; i < via_sgd_chnum; i++)
 1362               pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
 1363         for (i = 0; i < NWRCHANS; i++)
 1364               pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
 1365         if (via_dxs_chnum > 0)
 1366                 via_init_sysctls(dev);
 1367         device_printf(dev, "<VIA DXS %sabled: DXS%s %d / SGD %d / REC %d>\n",
 1368             (via_dxs_chnum > 0) ? "En" : "Dis", (via->dxs_src) ? "(SRC)" : "",
 1369             via_dxs_chnum, via_sgd_chnum, NWRCHANS);
 1370 
 1371         pcm_setstatus(dev, status);
 1372 
 1373         return (0);
 1374 bad:
 1375         if (via->codec)
 1376                 ac97_destroy(via->codec);
 1377         if (via->reg)
 1378                 bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
 1379         if (via->ih)
 1380                 bus_teardown_intr(dev, via->irq, via->ih);
 1381         if (via->irq)
 1382                 bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
 1383         if (via->parent_dmat)
 1384                 bus_dma_tag_destroy(via->parent_dmat);
 1385         if (via->sgd_addr)
 1386                 bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
 1387         if (via->sgd_table)
 1388                 bus_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap);
 1389         if (via->sgd_dmat)
 1390                 bus_dma_tag_destroy(via->sgd_dmat);
 1391         if (via->lock)
 1392                 snd_mtxfree(via->lock);
 1393         if (via)
 1394                 free(via, M_DEVBUF);
 1395         return (ENXIO);
 1396 }
 1397 
 1398 static int
 1399 via_detach(device_t dev)
 1400 {
 1401         int r;
 1402         struct via_info *via;
 1403 
 1404         r = pcm_unregister(dev);
 1405         if (r)
 1406                 return (r);
 1407 
 1408         via = pcm_getdevinfo(dev);
 1409 
 1410         if (via != NULL && (via->play_num != 0 || via->rec_num != 0)) {
 1411                 snd_mtxlock(via->lock);
 1412                 via->polling = 0;
 1413                 callout_stop(&via->poll_timer);
 1414                 snd_mtxunlock(via->lock);
 1415                 callout_drain(&via->poll_timer);
 1416         }
 1417 
 1418         bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
 1419         bus_teardown_intr(dev, via->irq, via->ih);
 1420         bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
 1421         bus_dma_tag_destroy(via->parent_dmat);
 1422         bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
 1423         bus_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap);
 1424         bus_dma_tag_destroy(via->sgd_dmat);
 1425         snd_mtxfree(via->lock);
 1426         free(via, M_DEVBUF);
 1427         return (0);
 1428 }
 1429 
 1430 static device_method_t via_methods[] = {
 1431         DEVMETHOD(device_probe,         via_probe),
 1432         DEVMETHOD(device_attach,        via_attach),
 1433         DEVMETHOD(device_detach,        via_detach),
 1434         { 0, 0}
 1435 };
 1436 
 1437 static driver_t via_driver = {
 1438         "pcm",
 1439         via_methods,
 1440         PCM_SOFTC_SIZE,
 1441 };
 1442 
 1443 DRIVER_MODULE(snd_via8233, pci, via_driver, 0, 0);
 1444 MODULE_DEPEND(snd_via8233, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
 1445 MODULE_VERSION(snd_via8233, 1);

Cache object: 5188b806bd41b5b5c31ca151205c31ac


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