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

Cache object: 580c2cb91ef90a0ce6c9b3211af77a83


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