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/via82c686.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) 2000 David Jones <dej@ox.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #ifdef HAVE_KERNEL_OPTION_HEADERS
   30 #include "opt_snd.h"
   31 #endif
   32 
   33 #include <dev/sound/pcm/sound.h>
   34 #include <dev/sound/pcm/ac97.h>
   35 
   36 #include <dev/pci/pcireg.h>
   37 #include <dev/pci/pcivar.h>
   38 #include <sys/sysctl.h>
   39 
   40 #include <dev/sound/pci/via82c686.h>
   41 
   42 SND_DECLARE_FILE("$FreeBSD$");
   43 
   44 #define VIA_PCI_ID 0x30581106
   45 #define NSEGS           4       /* Number of segments in SGD table */
   46 
   47 #define SEGS_PER_CHAN   (NSEGS/2)
   48 
   49 #define TIMEOUT 50
   50 #define VIA_DEFAULT_BUFSZ       0x1000
   51 
   52 #undef DEB
   53 #define DEB(x)
   54 
   55 /* we rely on this struct being packed to 64 bits */
   56 struct via_dma_op {
   57         u_int32_t ptr;
   58         u_int32_t flags;
   59 #define VIA_DMAOP_EOL         0x80000000
   60 #define VIA_DMAOP_FLAG        0x40000000
   61 #define VIA_DMAOP_STOP        0x20000000
   62 #define VIA_DMAOP_COUNT(x)    ((x)&0x00FFFFFF)
   63 };
   64 
   65 struct via_info;
   66 
   67 struct via_chinfo {
   68         struct via_info *parent;
   69         struct pcm_channel *channel;
   70         struct snd_dbuf *buffer;
   71         struct via_dma_op *sgd_table;
   72         bus_addr_t sgd_addr;
   73         int dir, blksz;
   74         int base, count, mode, ctrl;
   75 };
   76 
   77 struct via_info {
   78         bus_space_tag_t st;
   79         bus_space_handle_t sh;
   80         bus_dma_tag_t parent_dmat;
   81         bus_dma_tag_t sgd_dmat;
   82         bus_dmamap_t sgd_dmamap;
   83         bus_addr_t sgd_addr;
   84 
   85         struct resource *reg, *irq;
   86         int regid, irqid;
   87         void *ih;
   88         struct ac97_info *codec;
   89 
   90         unsigned int bufsz;
   91 
   92         struct via_chinfo pch, rch;
   93         struct via_dma_op *sgd_table;
   94         u_int16_t codec_caps;
   95         struct mtx *lock;
   96 };
   97 
   98 static u_int32_t via_fmt[] = {
   99         SND_FORMAT(AFMT_U8, 1, 0),
  100         SND_FORMAT(AFMT_U8, 2, 0),
  101         SND_FORMAT(AFMT_S16_LE, 1, 0),
  102         SND_FORMAT(AFMT_S16_LE, 2, 0),
  103         0
  104 };
  105 static struct pcmchan_caps via_vracaps = {4000, 48000, via_fmt, 0};
  106 static struct pcmchan_caps via_caps = {48000, 48000, via_fmt, 0};
  107 
  108 static __inline u_int32_t
  109 via_rd(struct via_info *via, int regno, int size)
  110 {
  111 
  112         switch (size) {
  113         case 1:
  114                 return bus_space_read_1(via->st, via->sh, regno);
  115         case 2:
  116                 return bus_space_read_2(via->st, via->sh, regno);
  117         case 4:
  118                 return bus_space_read_4(via->st, via->sh, regno);
  119         default:
  120                 return 0xFFFFFFFF;
  121         }
  122 }
  123 
  124 static __inline void
  125 via_wr(struct via_info *via, int regno, u_int32_t data, int size)
  126 {
  127 
  128         switch (size) {
  129         case 1:
  130                 bus_space_write_1(via->st, via->sh, regno, data);
  131                 break;
  132         case 2:
  133                 bus_space_write_2(via->st, via->sh, regno, data);
  134                 break;
  135         case 4:
  136                 bus_space_write_4(via->st, via->sh, regno, data);
  137                 break;
  138         }
  139 }
  140 
  141 /* -------------------------------------------------------------------- */
  142 /* Codec interface */
  143 
  144 static int
  145 via_waitready_codec(struct via_info *via)
  146 {
  147         int i;
  148 
  149         /* poll until codec not busy */
  150         for (i = 0; (i < TIMEOUT) &&
  151             (via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_BUSY); i++)
  152                 DELAY(1);
  153         if (i >= TIMEOUT) {
  154                 printf("via: codec busy\n");
  155                 return 1;
  156         }
  157 
  158         return 0;
  159 }
  160 
  161 static int
  162 via_waitvalid_codec(struct via_info *via)
  163 {
  164         int i;
  165 
  166         /* poll until codec valid */
  167         for (i = 0; (i < TIMEOUT) &&
  168             !(via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_PRIVALID); i++)
  169                     DELAY(1);
  170         if (i >= TIMEOUT) {
  171                 printf("via: codec invalid\n");
  172                 return 1;
  173         }
  174 
  175         return 0;
  176 }
  177 
  178 static int
  179 via_write_codec(kobj_t obj, void *addr, int reg, u_int32_t val)
  180 {
  181         struct via_info *via = addr;
  182 
  183         if (via_waitready_codec(via)) return -1;
  184 
  185         via_wr(via, VIA_CODEC_CTL, VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4);
  186 
  187         return 0;
  188 }
  189 
  190 static int
  191 via_read_codec(kobj_t obj, void *addr, int reg)
  192 {
  193         struct via_info *via = addr;
  194 
  195         if (via_waitready_codec(via))
  196                 return -1;
  197 
  198         via_wr(via, VIA_CODEC_CTL, VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4);
  199 
  200         if (via_waitready_codec(via))
  201                 return -1;
  202 
  203         if (via_waitvalid_codec(via))
  204                 return -1;
  205 
  206         return via_rd(via, VIA_CODEC_CTL, 2);
  207 }
  208 
  209 static kobj_method_t via_ac97_methods[] = {
  210         KOBJMETHOD(ac97_read,           via_read_codec),
  211         KOBJMETHOD(ac97_write,          via_write_codec),
  212         KOBJMETHOD_END
  213 };
  214 AC97_DECLARE(via_ac97);
  215 
  216 /* -------------------------------------------------------------------- */
  217 
  218 static int
  219 via_buildsgdt(struct via_chinfo *ch)
  220 {
  221         u_int32_t phys_addr, flag;
  222         int i, segs, seg_size;
  223 
  224         /*
  225          *  Build the scatter/gather DMA (SGD) table.
  226          *  There are four slots in the table: two for play, two for record.
  227          *  This creates two half-buffers, one of which is playing; the other
  228          *  is feeding.
  229          */
  230         seg_size = ch->blksz;
  231         segs = sndbuf_getsize(ch->buffer) / seg_size;
  232         phys_addr = sndbuf_getbufaddr(ch->buffer);
  233 
  234         for (i = 0; i < segs; i++) {
  235                 flag = (i == segs - 1)? VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
  236                 ch->sgd_table[i].ptr = phys_addr + (i * seg_size);
  237                 ch->sgd_table[i].flags = flag | seg_size;
  238         }
  239 
  240         return 0;
  241 }
  242 
  243 /* channel interface */
  244 static void *
  245 viachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
  246 {
  247         struct via_info *via = devinfo;
  248         struct via_chinfo *ch;
  249 
  250         snd_mtxlock(via->lock);
  251         if (dir == PCMDIR_PLAY) {
  252                 ch = &via->pch;
  253                 ch->base = VIA_PLAY_DMAOPS_BASE;
  254                 ch->count = VIA_PLAY_DMAOPS_COUNT;
  255                 ch->ctrl = VIA_PLAY_CONTROL;
  256                 ch->mode = VIA_PLAY_MODE;
  257                 ch->sgd_addr = via->sgd_addr;
  258                 ch->sgd_table = &via->sgd_table[0];
  259         } else {
  260                 ch = &via->rch;
  261                 ch->base = VIA_RECORD_DMAOPS_BASE;
  262                 ch->count = VIA_RECORD_DMAOPS_COUNT;
  263                 ch->ctrl = VIA_RECORD_CONTROL;
  264                 ch->mode = VIA_RECORD_MODE;
  265                 ch->sgd_addr = via->sgd_addr + sizeof(struct via_dma_op) * SEGS_PER_CHAN;
  266                 ch->sgd_table = &via->sgd_table[SEGS_PER_CHAN];
  267         }
  268 
  269         ch->parent = via;
  270         ch->channel = c;
  271         ch->buffer = b;
  272         ch->dir = dir;
  273         snd_mtxunlock(via->lock);
  274 
  275         if (sndbuf_alloc(ch->buffer, via->parent_dmat, 0, via->bufsz) != 0)
  276                 return NULL;
  277 
  278         return ch;
  279 }
  280 
  281 static int
  282 viachan_setformat(kobj_t obj, void *data, u_int32_t format)
  283 {
  284         struct via_chinfo *ch = data;
  285         struct via_info *via = ch->parent;
  286         int mode, mode_set;
  287 
  288         mode_set = 0;
  289         if (AFMT_CHANNEL(format) > 1)
  290                 mode_set |= VIA_RPMODE_STEREO;
  291         if (format & AFMT_S16_LE)
  292                 mode_set |= VIA_RPMODE_16BIT;
  293 
  294         DEB(printf("set format: dir = %d, format=%x\n", ch->dir, format));
  295         snd_mtxlock(via->lock);
  296         mode = via_rd(via, ch->mode, 1);
  297         mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
  298         mode |= mode_set;
  299         via_wr(via, ch->mode, mode, 1);
  300         snd_mtxunlock(via->lock);
  301 
  302         return 0;
  303 }
  304 
  305 static u_int32_t
  306 viachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  307 {
  308         struct via_chinfo *ch = data;
  309         struct via_info *via = ch->parent;
  310         int reg;
  311 
  312         /*
  313          *  Basic AC'97 defines a 48 kHz sample rate only.  For other rates,
  314          *  upsampling is required.
  315          *
  316          *  The VT82C686A does not perform upsampling, and neither do we.
  317          *  If the codec supports variable-rate audio (i.e. does the upsampling
  318          *  itself), then negotiate the rate with the codec.  Otherwise,
  319          *  return 48 kHz cuz that's all you got.
  320          */
  321         if (via->codec_caps & AC97_EXTCAP_VRA) {
  322                 reg = (ch->dir == PCMDIR_PLAY)? AC97_REGEXT_FDACRATE : AC97_REGEXT_LADCRATE;
  323                 return ac97_setrate(via->codec, reg, speed);
  324         } else
  325                 return 48000;
  326 }
  327 
  328 static u_int32_t
  329 viachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  330 {
  331         struct via_chinfo *ch = data;
  332 
  333         ch->blksz = blocksize;
  334         sndbuf_resize(ch->buffer, SEGS_PER_CHAN, ch->blksz);
  335 
  336         return ch->blksz;
  337 }
  338 
  339 static int
  340 viachan_trigger(kobj_t obj, void *data, int go)
  341 {
  342         struct via_chinfo *ch = data;
  343         struct via_info *via = ch->parent;
  344         bus_addr_t sgd_addr = ch->sgd_addr;
  345 
  346         if (!PCMTRIG_COMMON(go))
  347                 return 0;
  348 
  349         DEB(printf("ado located at va=%p pa=%x\n", ch->sgd_table, sgd_addr));
  350 
  351         snd_mtxlock(via->lock);
  352         if (go == PCMTRIG_START) {
  353                 via_buildsgdt(ch);
  354                 via_wr(via, ch->base, sgd_addr, 4);
  355                 via_wr(via, ch->ctrl, VIA_RPCTRL_START, 1);
  356         } else
  357                 via_wr(via, ch->ctrl, VIA_RPCTRL_TERMINATE, 1);
  358         snd_mtxunlock(via->lock);
  359 
  360         DEB(printf("viachan_trigger: go=%d\n", go));
  361         return 0;
  362 }
  363 
  364 static u_int32_t
  365 viachan_getptr(kobj_t obj, void *data)
  366 {
  367         struct via_chinfo *ch = data;
  368         struct via_info *via = ch->parent;
  369         bus_addr_t sgd_addr = ch->sgd_addr;
  370         u_int32_t ptr, base, base1, len, seg;
  371 
  372         snd_mtxlock(via->lock);
  373         base1 = via_rd(via, ch->base, 4);
  374         len = via_rd(via, ch->count, 4);
  375         base = via_rd(via, ch->base, 4);
  376         if (base != base1)      /* Avoid race hazard */
  377                 len = via_rd(via, ch->count, 4);
  378         snd_mtxunlock(via->lock);
  379 
  380         DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
  381 
  382         /* Base points to SGD segment to do, one past current */
  383 
  384         /* Determine how many segments have been done */
  385         seg = (base - sgd_addr) / sizeof(struct via_dma_op);
  386         if (seg == 0)
  387                 seg = SEGS_PER_CHAN;
  388 
  389         /* Now work out offset: seg less count */
  390         ptr = (seg * sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN) - len;
  391         if (ch->dir == PCMDIR_REC) {
  392                 /* DMA appears to operate on memory 'lines' of 32 bytes */
  393                 /* so don't return any part line - it isn't in RAM yet  */
  394                 ptr = ptr & ~0x1f;
  395         }
  396 
  397         DEB(printf("return ptr=%u\n", ptr));
  398         return ptr;
  399 }
  400 
  401 static struct pcmchan_caps *
  402 viachan_getcaps(kobj_t obj, void *data)
  403 {
  404         struct via_chinfo *ch = data;
  405         struct via_info *via = ch->parent;
  406 
  407         return (via->codec_caps & AC97_EXTCAP_VRA)? &via_vracaps : &via_caps;
  408 }
  409 
  410 static kobj_method_t viachan_methods[] = {
  411         KOBJMETHOD(channel_init,                viachan_init),
  412         KOBJMETHOD(channel_setformat,           viachan_setformat),
  413         KOBJMETHOD(channel_setspeed,            viachan_setspeed),
  414         KOBJMETHOD(channel_setblocksize,        viachan_setblocksize),
  415         KOBJMETHOD(channel_trigger,             viachan_trigger),
  416         KOBJMETHOD(channel_getptr,              viachan_getptr),
  417         KOBJMETHOD(channel_getcaps,             viachan_getcaps),
  418         KOBJMETHOD_END
  419 };
  420 CHANNEL_DECLARE(viachan);
  421 
  422 /* -------------------------------------------------------------------- */
  423 
  424 static void
  425 via_intr(void *p)
  426 {
  427         struct via_info *via = p;
  428 
  429         /* DEB(printf("viachan_intr\n")); */
  430         /* Read channel */
  431         snd_mtxlock(via->lock);
  432         if (via_rd(via, VIA_PLAY_STAT, 1) & VIA_RPSTAT_INTR) {
  433                 via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1);
  434                 snd_mtxunlock(via->lock);
  435                 chn_intr(via->pch.channel);
  436                 snd_mtxlock(via->lock);
  437         }
  438 
  439         /* Write channel */
  440         if (via_rd(via, VIA_RECORD_STAT, 1) & VIA_RPSTAT_INTR) {
  441                 via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1);
  442                 snd_mtxunlock(via->lock);
  443                 chn_intr(via->rch.channel);
  444                 return;
  445         }
  446         snd_mtxunlock(via->lock);
  447 }
  448 
  449 /*
  450  *  Probe and attach the card
  451  */
  452 static int
  453 via_probe(device_t dev)
  454 {
  455         if (pci_get_devid(dev) == VIA_PCI_ID) {
  456                 device_set_desc(dev, "VIA VT82C686A");
  457                 return BUS_PROBE_DEFAULT;
  458         }
  459         return ENXIO;
  460 }
  461 
  462 static void
  463 dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
  464 {
  465         struct via_info *via = (struct via_info *)p;
  466         via->sgd_addr = bds->ds_addr;
  467 }
  468 
  469 static int
  470 via_attach(device_t dev)
  471 {
  472         struct via_info *via = NULL;
  473         char status[SND_STATUSLEN];
  474         u_int32_t data, cnt;
  475 
  476         via = malloc(sizeof(*via), M_DEVBUF, M_WAITOK | M_ZERO);
  477         via->lock = snd_mtxcreate(device_get_nameunit(dev),
  478             "snd_via82c686 softc");
  479 
  480         pci_enable_busmaster(dev);
  481 
  482         /* Wake up and reset AC97 if necessary */
  483         data = pci_read_config(dev, VIA_AC97STATUS, 1);
  484 
  485         if ((data & VIA_AC97STATUS_RDY) == 0) {
  486                 /* Cold reset per ac97r2.3 spec (page 95) */
  487                 pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_EN, 1);                        /* Assert low */
  488                 DELAY(100);                                                                     /* Wait T_rst_low */
  489                 pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_EN | VIA_ACLINK_NRST, 1);      /* Assert high */
  490                 DELAY(5);                                                                       /* Wait T_rst2clk */
  491                 pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_EN, 1);                        /* Assert low */
  492         } else {
  493                 /* Warm reset */
  494                 pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_EN, 1);                        /* Force no sync */
  495                 DELAY(100);
  496                 pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_EN | VIA_ACLINK_SYNC, 1);      /* Sync */
  497                 DELAY(5);                                                                       /* Wait T_sync_high */
  498                 pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_EN, 1);                        /* Force no sync */
  499                 DELAY(5);                                                                       /* Wait T_sync2clk */
  500         }
  501 
  502         /* Power everything up */
  503         pci_write_config(dev, VIA_ACLINKCTRL, VIA_ACLINK_DESIRED, 1);   
  504 
  505         /* Wait for codec to become ready (largest reported delay here 310ms) */
  506         for (cnt = 0; cnt < 2000; cnt++) {
  507                 data = pci_read_config(dev, VIA_AC97STATUS, 1);
  508                 if (data & VIA_AC97STATUS_RDY) 
  509                         break;
  510                 DELAY(5000);
  511         }
  512 
  513         via->regid = PCIR_BAR(0);
  514         via->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
  515                 &via->regid, RF_ACTIVE);
  516         if (!via->reg) {
  517                 device_printf(dev, "cannot allocate bus resource.");
  518                 goto bad;
  519         }
  520         via->st = rman_get_bustag(via->reg);
  521         via->sh = rman_get_bushandle(via->reg);
  522 
  523         via->bufsz = pcm_getbuffersize(dev, 4096, VIA_DEFAULT_BUFSZ, 65536);
  524 
  525         via->irqid = 0;
  526         via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
  527                 RF_ACTIVE | RF_SHAREABLE);
  528         if (!via->irq || snd_setup_intr(dev, via->irq, INTR_MPSAFE, via_intr, via, &via->ih)) {
  529                 device_printf(dev, "unable to map interrupt\n");
  530                 goto bad;
  531         }
  532 
  533         via_wr(via, VIA_PLAY_MODE, VIA_RPMODE_AUTOSTART | VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
  534         via_wr(via, VIA_RECORD_MODE, VIA_RPMODE_AUTOSTART | VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1);
  535 
  536         via->codec = AC97_CREATE(dev, via, via_ac97);
  537         if (!via->codec)
  538                 goto bad;
  539 
  540         if (mixer_init(dev, ac97_getmixerclass(), via->codec))
  541                 goto bad;
  542 
  543         via->codec_caps = ac97_getextcaps(via->codec);
  544         ac97_setextmode(via->codec, 
  545                         via->codec_caps & (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM));
  546 
  547         /* DMA tag for buffers */
  548         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
  549                 /*boundary*/0,
  550                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  551                 /*highaddr*/BUS_SPACE_MAXADDR,
  552                 /*filter*/NULL, /*filterarg*/NULL,
  553                 /*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
  554                 /*flags*/0, /*lockfunc*/NULL,
  555                 /*lockarg*/NULL, &via->parent_dmat) != 0) {
  556                 device_printf(dev, "unable to create dma tag\n");
  557                 goto bad;
  558         }
  559 
  560         /*
  561          *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
  562          *  requires a list in memory of work to do.  We need only 16 bytes
  563          *  for this list, and it is wasteful to allocate 16K.
  564          */
  565         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
  566                 /*boundary*/0,
  567                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  568                 /*highaddr*/BUS_SPACE_MAXADDR,
  569                 /*filter*/NULL, /*filterarg*/NULL,
  570                 /*maxsize*/NSEGS * sizeof(struct via_dma_op),
  571                 /*nsegments*/1, /*maxsegz*/0x3ffff,
  572                 /*flags*/0, /*lockfunc*/NULL,
  573                 /*lockarg*/NULL, &via->sgd_dmat) != 0) {
  574                 device_printf(dev, "unable to create dma tag\n");
  575                 goto bad;
  576         }
  577 
  578         if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table,
  579             BUS_DMA_NOWAIT, &via->sgd_dmamap) != 0)
  580                 goto bad;
  581         if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table,
  582             NSEGS * sizeof(struct via_dma_op), dma_cb, via, 0) != 0)
  583                 goto bad;
  584 
  585         snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd %s",
  586                  rman_get_start(via->reg), rman_get_start(via->irq),
  587                  PCM_KLDSTRING(snd_via82c686));
  588 
  589         /* Register */
  590         if (pcm_register(dev, via, 1, 1)) goto bad;
  591         pcm_addchan(dev, PCMDIR_PLAY, &viachan_class, via);
  592         pcm_addchan(dev, PCMDIR_REC, &viachan_class, via);
  593         pcm_setstatus(dev, status);
  594         return 0;
  595 bad:
  596         if (via->codec) ac97_destroy(via->codec);
  597         if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
  598         if (via->ih) bus_teardown_intr(dev, via->irq, via->ih);
  599         if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
  600         if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
  601         if (via->sgd_addr) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
  602         if (via->sgd_table) bus_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap);
  603         if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
  604         if (via->lock) snd_mtxfree(via->lock);
  605         if (via) free(via, M_DEVBUF);
  606         return ENXIO;
  607 }
  608 
  609 static int
  610 via_detach(device_t dev)
  611 {
  612         int r;
  613         struct via_info *via = NULL;
  614 
  615         r = pcm_unregister(dev);
  616         if (r)
  617                 return r;
  618 
  619         via = pcm_getdevinfo(dev);
  620         bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
  621         bus_teardown_intr(dev, via->irq, via->ih);
  622         bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
  623         bus_dma_tag_destroy(via->parent_dmat);
  624         bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
  625         bus_dmamem_free(via->sgd_dmat, via->sgd_table, via->sgd_dmamap);
  626         bus_dma_tag_destroy(via->sgd_dmat);
  627         snd_mtxfree(via->lock);
  628         free(via, M_DEVBUF);
  629         return 0;
  630 }
  631 
  632 static device_method_t via_methods[] = {
  633         DEVMETHOD(device_probe,         via_probe),
  634         DEVMETHOD(device_attach,        via_attach),
  635         DEVMETHOD(device_detach,        via_detach),
  636         { 0, 0}
  637 };
  638 
  639 static driver_t via_driver = {
  640         "pcm",
  641         via_methods,
  642         PCM_SOFTC_SIZE,
  643 };
  644 
  645 DRIVER_MODULE(snd_via82c686, pci, via_driver, 0, 0);
  646 MODULE_DEPEND(snd_via82c686, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  647 MODULE_VERSION(snd_via82c686, 1);

Cache object: 055819977f6a1a795af62a2476dcd11b


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