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  * Copyright (c) 2002 Orion Hodson <orion@freebsd.org>
    3  * Portions of this code derived from via82c686.c:
    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 /*
   30  * Credits due to:
   31  *
   32  * Grzybowski Rafal, Russell Davies, Mark Handley, Daniel O'Connor for
   33  * comments, machine time, testing patches, and patience.  VIA for
   34  * providing specs.  ALSA for helpful comments and some register poke
   35  * ordering.  
   36  */
   37 
   38 #include <dev/sound/pcm/sound.h>
   39 #include <dev/sound/pcm/ac97.h>
   40 
   41 #include <dev/pci/pcireg.h>
   42 #include <dev/pci/pcivar.h>
   43 #include <sys/sysctl.h>
   44 
   45 #include <dev/sound/pci/via8233.h>
   46 
   47 SND_DECLARE_FILE("$FreeBSD$");
   48 
   49 #define VIA8233_PCI_ID 0x30591106
   50 
   51 #define VIA8233_REV_ID_8233PRE  0x10
   52 #define VIA8233_REV_ID_8233C    0x20
   53 #define VIA8233_REV_ID_8233     0x30
   54 #define VIA8233_REV_ID_8233A    0x40
   55 #define VIA8233_REV_ID_8235     0x50
   56 #define VIA8233_REV_ID_8237     0x60
   57 
   58 #define SEGS_PER_CHAN   2                       /* Segments per channel */
   59 #define NDXSCHANS       4                       /* No of DXS channels */
   60 #define NMSGDCHANS      1                       /* No of multichannel SGD */
   61 #define NWRCHANS        1                       /* No of write channels */
   62 #define NCHANS          (NWRCHANS + NDXSCHANS + NMSGDCHANS)
   63 #define NSEGS           NCHANS * SEGS_PER_CHAN  /* Segments in SGD table */
   64 
   65 #define VIA_DEFAULT_BUFSZ       0x1000
   66 
   67 /* we rely on this struct being packed to 64 bits */
   68 struct via_dma_op {
   69         volatile u_int32_t ptr;
   70         volatile u_int32_t flags;
   71 #define VIA_DMAOP_EOL         0x80000000
   72 #define VIA_DMAOP_FLAG        0x40000000
   73 #define VIA_DMAOP_STOP        0x20000000
   74 #define VIA_DMAOP_COUNT(x)    ((x)&0x00FFFFFF)
   75 };
   76 
   77 struct via_info;
   78 
   79 struct via_chinfo {
   80         struct via_info *parent;
   81         struct pcm_channel *channel;
   82         struct snd_dbuf *buffer;
   83         struct via_dma_op *sgd_table;
   84         bus_addr_t sgd_addr;
   85         int dir, blksz;
   86         int rbase;
   87 };
   88 
   89 struct via_info {
   90         bus_space_tag_t st;
   91         bus_space_handle_t sh;
   92         bus_dma_tag_t parent_dmat;
   93         bus_dma_tag_t sgd_dmat;
   94         bus_dmamap_t sgd_dmamap;
   95         bus_addr_t sgd_addr;
   96 
   97         struct resource *reg, *irq;
   98         int regid, irqid;
   99         void *ih;
  100         struct ac97_info *codec;
  101 
  102         unsigned int bufsz;
  103 
  104         struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
  105         struct via_chinfo rch[NWRCHANS];
  106         struct via_dma_op *sgd_table;
  107         u_int16_t codec_caps;
  108         u_int16_t n_dxs_registered;
  109 };
  110 
  111 static u_int32_t via_fmt[] = {
  112         AFMT_U8,
  113         AFMT_STEREO | AFMT_U8,
  114         AFMT_S16_LE,
  115         AFMT_STEREO | AFMT_S16_LE,
  116         0
  117 };
  118 
  119 static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
  120 static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
  121 
  122 static u_int32_t
  123 via_rd(struct via_info *via, int regno, int size)
  124 {
  125         switch (size) {
  126         case 1:
  127                 return bus_space_read_1(via->st, via->sh, regno);
  128         case 2:
  129                 return bus_space_read_2(via->st, via->sh, regno);
  130         case 4:
  131                 return bus_space_read_4(via->st, via->sh, regno);
  132         default:
  133                 return 0xFFFFFFFF;
  134         }
  135 }
  136 
  137 static void
  138 via_wr(struct via_info *via, int regno, u_int32_t data, int size)
  139 {
  140 
  141         switch (size) {
  142         case 1:
  143                 bus_space_write_1(via->st, via->sh, regno, data);
  144                 break;
  145         case 2:
  146                 bus_space_write_2(via->st, via->sh, regno, data);
  147                 break;
  148         case 4:
  149                 bus_space_write_4(via->st, via->sh, regno, data);
  150                 break;
  151         }
  152 }
  153 
  154 /* -------------------------------------------------------------------- */
  155 /* Codec interface */
  156 
  157 static int
  158 via_waitready_codec(struct via_info *via)
  159 {
  160         int i;
  161 
  162         /* poll until codec not busy */
  163         for (i = 0; i < 1000; i++) {
  164                 if ((via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_BUSY) == 0)
  165                         return 0;
  166                 DELAY(1);
  167         }
  168         printf("via: codec busy\n");
  169         return 1;
  170 }
  171 
  172 static int
  173 via_waitvalid_codec(struct via_info *via)
  174 {
  175         int i;
  176 
  177         /* poll until codec valid */
  178         for (i = 0; i < 1000; i++) {
  179                 if (via_rd(via, VIA_AC97_CONTROL, 4) & VIA_AC97_CODEC00_VALID)
  180                         return 0;
  181                 DELAY(1);
  182         }
  183         printf("via: codec invalid\n");
  184         return 1;
  185 }
  186 
  187 static int
  188 via_write_codec(kobj_t obj, void *addr, int reg, u_int32_t val)
  189 {
  190         struct via_info *via = addr;
  191 
  192         if (via_waitready_codec(via)) return -1;
  193 
  194         via_wr(via, VIA_AC97_CONTROL, 
  195                VIA_AC97_CODEC00_VALID | VIA_AC97_INDEX(reg) |
  196                VIA_AC97_DATA(val), 4);
  197 
  198         return 0;
  199 }
  200 
  201 static int
  202 via_read_codec(kobj_t obj, void *addr, int reg)
  203 {
  204         struct via_info *via = addr;
  205 
  206         if (via_waitready_codec(via))
  207                 return -1;
  208 
  209         via_wr(via, VIA_AC97_CONTROL, VIA_AC97_CODEC00_VALID | 
  210                VIA_AC97_READ | VIA_AC97_INDEX(reg), 4);
  211 
  212         if (via_waitready_codec(via))
  213                 return -1;
  214 
  215         if (via_waitvalid_codec(via))
  216                 return -1;
  217 
  218         return via_rd(via, VIA_AC97_CONTROL, 2);
  219 }
  220 
  221 static kobj_method_t via_ac97_methods[] = {
  222         KOBJMETHOD(ac97_read,           via_read_codec),
  223         KOBJMETHOD(ac97_write,          via_write_codec),
  224         { 0, 0 }
  225 };
  226 AC97_DECLARE(via_ac97);
  227 
  228 /* -------------------------------------------------------------------- */
  229 
  230 static int
  231 via_buildsgdt(struct via_chinfo *ch)
  232 {
  233         u_int32_t phys_addr, flag;
  234         int i, seg_size;
  235 
  236         seg_size = sndbuf_getsize(ch->buffer) / SEGS_PER_CHAN;
  237         phys_addr = sndbuf_getbufaddr(ch->buffer);
  238 
  239         for (i = 0; i < SEGS_PER_CHAN; i++) {
  240                 flag = (i == SEGS_PER_CHAN - 1) ? VIA_DMAOP_EOL : VIA_DMAOP_FLAG;
  241                 ch->sgd_table[i].ptr = phys_addr + (i * seg_size);
  242                 ch->sgd_table[i].flags = flag | seg_size;
  243         }
  244 
  245         return 0;
  246 }
  247 
  248 /* -------------------------------------------------------------------- */
  249 /* Format setting functions */
  250 
  251 static int
  252 via8233wr_setformat(kobj_t obj, void *data, u_int32_t format)
  253 {
  254         struct via_chinfo *ch = data;
  255         struct via_info *via = ch->parent;
  256         
  257         u_int32_t f = WR_FORMAT_STOP_INDEX;
  258 
  259         if (format & AFMT_STEREO)
  260                 f |= WR_FORMAT_STEREO;
  261         if (format & AFMT_S16_LE)
  262                 f |= WR_FORMAT_16BIT;
  263         via_wr(via, VIA_WR0_FORMAT, f, 4);
  264 
  265         return 0;
  266 }
  267 
  268 static int
  269 via8233dxs_setformat(kobj_t obj, void *data, u_int32_t format)
  270 {
  271         struct via_chinfo *ch = data;
  272         struct via_info *via = ch->parent;
  273 
  274         u_int32_t r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
  275         u_int32_t v = via_rd(via, r, 4);
  276 
  277         v &= ~(VIA8233_DXS_RATEFMT_STEREO | VIA8233_DXS_RATEFMT_16BIT);
  278         if (format & AFMT_STEREO)
  279                 v |= VIA8233_DXS_RATEFMT_STEREO;
  280         if (format & AFMT_16BIT)  
  281                 v |= VIA8233_DXS_RATEFMT_16BIT;
  282         via_wr(via, r, v, 4);
  283 
  284         return 0;
  285 }
  286 
  287 static int
  288 via8233msgd_setformat(kobj_t obj, void *data, u_int32_t format)
  289 {
  290         struct via_chinfo *ch = data;
  291         struct via_info *via = ch->parent;
  292 
  293         u_int32_t s = 0xff000000;
  294         u_int8_t  v = (format & AFMT_S16_LE) ? MC_SGD_16BIT : MC_SGD_8BIT;
  295 
  296         if (format & AFMT_STEREO) {
  297                 v |= MC_SGD_CHANNELS(2);
  298                 s |= SLOT3(1) | SLOT4(2);
  299         } else {
  300                 v |= MC_SGD_CHANNELS(1);
  301                 s |= SLOT3(1) | SLOT4(1);
  302         }
  303 
  304         via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
  305         via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
  306 
  307         return 0;
  308 }
  309 
  310 /* -------------------------------------------------------------------- */
  311 /* Speed setting functions */
  312 
  313 static int
  314 via8233wr_setspeed(kobj_t obj, void *data, u_int32_t speed)
  315 {
  316         struct via_chinfo *ch = data;
  317         struct via_info *via = ch->parent;
  318 
  319         u_int32_t spd = 48000;
  320         if (via->codec_caps & AC97_EXTCAP_VRA) {
  321                 spd = ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed);
  322         }
  323         return spd;
  324 }
  325 
  326 static int
  327 via8233dxs_setspeed(kobj_t obj, void *data, u_int32_t speed)
  328 {
  329         struct via_chinfo *ch = data;
  330         struct via_info *via = ch->parent;
  331 
  332         u_int32_t r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
  333         u_int32_t v = via_rd(via, r, 4) & ~VIA8233_DXS_RATEFMT_48K;
  334 
  335         /* Careful to avoid overflow (divide by 48 per vt8233c docs) */
  336 
  337         v |= VIA8233_DXS_RATEFMT_48K * (speed / 48) / (48000 / 48);
  338         via_wr(via, r, v, 4);
  339 
  340         return speed;
  341 }
  342 
  343 static int
  344 via8233msgd_setspeed(kobj_t obj, void *data, u_int32_t speed)
  345 {
  346         struct via_chinfo *ch = data;
  347         struct via_info *via = ch->parent;
  348 
  349         if (via->codec_caps & AC97_EXTCAP_VRA)
  350                 return ac97_setrate(via->codec, AC97_REGEXT_FDACRATE, speed); 
  351 
  352         return 48000;
  353 }
  354 
  355 /* -------------------------------------------------------------------- */
  356 /* Format probing functions */
  357 
  358 static struct pcmchan_caps *
  359 via8233wr_getcaps(kobj_t obj, void *data)
  360 {
  361         struct via_chinfo *ch = data;
  362         struct via_info *via = ch->parent;
  363 
  364         /* Controlled by ac97 registers */
  365         if (via->codec_caps & AC97_EXTCAP_VRA) 
  366                 return &via_vracaps;
  367         return &via_caps;
  368 }
  369 
  370 static struct pcmchan_caps *
  371 via8233dxs_getcaps(kobj_t obj, void *data)
  372 {
  373         /* Controlled by onboard registers */
  374         return &via_caps;
  375 }
  376 
  377 static struct pcmchan_caps *
  378 via8233msgd_getcaps(kobj_t obj, void *data)
  379 {
  380         struct via_chinfo *ch = data;
  381         struct via_info *via = ch->parent;
  382 
  383         /* Controlled by ac97 registers */
  384         if (via->codec_caps & AC97_EXTCAP_VRA) 
  385                 return &via_vracaps;
  386         return &via_caps;
  387 }
  388 
  389 /* -------------------------------------------------------------------- */
  390 /* Common functions */
  391 
  392 static int
  393 via8233chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  394 {
  395         struct via_chinfo *ch = data;
  396         sndbuf_resize(ch->buffer, SEGS_PER_CHAN, blocksize);
  397         ch->blksz = sndbuf_getblksz(ch->buffer);
  398         return ch->blksz;
  399 }
  400 
  401 static int
  402 via8233chan_getptr(kobj_t obj, void *data)
  403 {
  404         struct via_chinfo *ch = data;
  405         struct via_info *via = ch->parent;
  406 
  407         u_int32_t v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
  408         u_int32_t index = v >> 24;              /* Last completed buffer */
  409         u_int32_t count = v & 0x00ffffff;       /* Bytes remaining */
  410         int ptr = (index + 1) * ch->blksz - count;
  411         ptr %= SEGS_PER_CHAN * ch->blksz;       /* Wrap to available space */
  412 
  413         return ptr;
  414 }
  415 
  416 static void
  417 via8233chan_reset(struct via_info *via, struct via_chinfo *ch)
  418 {
  419         via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
  420         via_wr(via, ch->rbase + VIA_RP_CONTROL, 0x00, 1);
  421         via_wr(via, ch->rbase + VIA_RP_STATUS, 
  422                SGD_STATUS_EOL | SGD_STATUS_FLAG, 1);
  423 }
  424 
  425 /* -------------------------------------------------------------------- */
  426 /* Channel initialization functions */
  427 
  428 static void
  429 via8233chan_sgdinit(struct via_info *via, struct via_chinfo *ch, int chnum)
  430 {
  431         ch->sgd_table = &via->sgd_table[chnum * SEGS_PER_CHAN];
  432         ch->sgd_addr = via->sgd_addr + chnum * SEGS_PER_CHAN * sizeof(struct via_dma_op);
  433 }
  434 
  435 static void*
  436 via8233wr_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  437                struct pcm_channel *c, int dir)
  438 {
  439         struct via_info *via = devinfo;
  440         struct via_chinfo *ch = &via->rch[c->num];
  441 
  442         ch->parent = via;
  443         ch->channel = c;
  444         ch->buffer = b;
  445         ch->dir = dir;
  446 
  447         ch->rbase = VIA_WR_BASE(c->num);
  448         via_wr(via, ch->rbase + VIA_WR_RP_SGD_FORMAT, WR_FIFO_ENABLE, 1);
  449 
  450         if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
  451                 return NULL;
  452         via8233chan_sgdinit(via, ch, c->num);
  453         via8233chan_reset(via, ch);
  454 
  455         return ch;
  456 }
  457 
  458 static void*
  459 via8233dxs_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  460                 struct pcm_channel *c, int dir)
  461 {
  462         struct via_info *via = devinfo;
  463         struct via_chinfo *ch = &via->pch[c->num];
  464 
  465         ch->parent = via;
  466         ch->channel = c;
  467         ch->buffer = b;
  468         ch->dir = dir;
  469 
  470         /*
  471          * All cards apparently support DXS3, but not other DXS
  472          * channels.  We therefore want to align first DXS channel to
  473          * DXS3.
  474          */
  475         ch->rbase = VIA_DXS_BASE(NDXSCHANS - 1 - via->n_dxs_registered);
  476         via->n_dxs_registered++;
  477 
  478         if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
  479                 return NULL;
  480         via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
  481         via8233chan_reset(via, ch);
  482 
  483         return ch;
  484 }
  485 
  486 static void*
  487 via8233msgd_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
  488                  struct pcm_channel *c, int dir)
  489 {
  490         struct via_info *via = devinfo;
  491         struct via_chinfo *ch = &via->pch[c->num];
  492 
  493         ch->parent = via;
  494         ch->channel = c;
  495         ch->buffer = b;
  496         ch->dir = dir;
  497         ch->rbase = VIA_MC_SGD_STATUS;
  498 
  499         if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
  500                 return NULL;
  501         via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
  502         via8233chan_reset(via, ch);
  503 
  504         return ch;
  505 }
  506 
  507 static void
  508 via8233chan_mute(struct via_info *via, struct via_chinfo *ch, int muted)
  509 {
  510         if (BASE_IS_VIA_DXS_REG(ch->rbase)) {
  511                 int r;
  512                 muted = (muted) ? VIA8233_DXS_MUTE : 0;
  513                 via_wr(via, ch->rbase + VIA8233_RP_DXS_LVOL, muted, 1);
  514                 via_wr(via, ch->rbase + VIA8233_RP_DXS_RVOL, muted, 1);
  515                 r = via_rd(via, ch->rbase + VIA8233_RP_DXS_LVOL, 1) & VIA8233_DXS_MUTE;
  516                 if (r != muted) {
  517                         printf("via: failed to set dxs volume "
  518                                "(dxs base 0x%02x).\n", ch->rbase);
  519                 }
  520         }
  521 }
  522 
  523 static int
  524 via8233chan_trigger(kobj_t obj, void* data, int go)
  525 {
  526         struct via_chinfo *ch = data;
  527         struct via_info *via = ch->parent;
  528 
  529         switch(go) {
  530         case PCMTRIG_START:
  531                 via_buildsgdt(ch);
  532                 via8233chan_mute(via, ch, 0);
  533                 via_wr(via, ch->rbase + VIA_RP_TABLE_PTR, ch->sgd_addr, 4);
  534                 via_wr(via, ch->rbase + VIA_RP_CONTROL,
  535                        SGD_CONTROL_START | SGD_CONTROL_AUTOSTART |
  536                        SGD_CONTROL_I_EOL | SGD_CONTROL_I_FLAG, 1);
  537                 break;
  538         case PCMTRIG_STOP:
  539         case PCMTRIG_ABORT:
  540                 via_wr(via, ch->rbase + VIA_RP_CONTROL, SGD_CONTROL_STOP, 1);
  541                 via8233chan_mute(via, ch, 1);
  542                 via8233chan_reset(via, ch);
  543                 break;
  544         }
  545         return 0;
  546 }
  547 
  548 static kobj_method_t via8233wr_methods[] = {
  549         KOBJMETHOD(channel_init,                via8233wr_init),
  550         KOBJMETHOD(channel_setformat,           via8233wr_setformat),
  551         KOBJMETHOD(channel_setspeed,            via8233wr_setspeed),
  552         KOBJMETHOD(channel_getcaps,             via8233wr_getcaps),
  553         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
  554         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
  555         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
  556         { 0, 0 }
  557 };
  558 CHANNEL_DECLARE(via8233wr);
  559 
  560 static kobj_method_t via8233dxs_methods[] = {
  561         KOBJMETHOD(channel_init,                via8233dxs_init),
  562         KOBJMETHOD(channel_setformat,           via8233dxs_setformat),
  563         KOBJMETHOD(channel_setspeed,            via8233dxs_setspeed),
  564         KOBJMETHOD(channel_getcaps,             via8233dxs_getcaps),
  565         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
  566         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
  567         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
  568         { 0, 0 }
  569 };
  570 CHANNEL_DECLARE(via8233dxs);
  571 
  572 static kobj_method_t via8233msgd_methods[] = {
  573         KOBJMETHOD(channel_init,                via8233msgd_init),
  574         KOBJMETHOD(channel_setformat,           via8233msgd_setformat),
  575         KOBJMETHOD(channel_setspeed,            via8233msgd_setspeed),
  576         KOBJMETHOD(channel_getcaps,             via8233msgd_getcaps),
  577         KOBJMETHOD(channel_setblocksize,        via8233chan_setblocksize),
  578         KOBJMETHOD(channel_trigger,             via8233chan_trigger),
  579         KOBJMETHOD(channel_getptr,              via8233chan_getptr),
  580         { 0, 0 }
  581 };
  582 CHANNEL_DECLARE(via8233msgd);
  583 
  584 /* -------------------------------------------------------------------- */
  585 
  586 static void
  587 via_intr(void *p)
  588 {
  589         struct via_info *via = p;
  590         int i, stat;
  591 
  592         /* Poll playback channels */
  593         for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
  594                 if (via->pch[i].rbase == 0)
  595                         continue;
  596                 stat = via->pch[i].rbase + VIA_RP_STATUS;
  597                 if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
  598                         via_wr(via, stat, SGD_STATUS_INTR, 1);
  599                         chn_intr(via->pch[i].channel);
  600                 }
  601         }
  602         
  603         /* Poll record channels */
  604         for (i = 0; i < NWRCHANS; i++) {
  605                 if (via->rch[i].rbase == 0)
  606                         continue;
  607                 stat = via->rch[i].rbase + VIA_RP_STATUS;
  608                 if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
  609                         via_wr(via, stat, SGD_STATUS_INTR, 1);
  610                         chn_intr(via->rch[i].channel);
  611                 }
  612         }
  613 }
  614 
  615 /*
  616  *  Probe and attach the card
  617  */
  618 static int
  619 via_probe(device_t dev)
  620 {
  621         switch(pci_get_devid(dev)) {
  622         case VIA8233_PCI_ID:
  623                 switch(pci_get_revid(dev)) {
  624                 case VIA8233_REV_ID_8233PRE: 
  625                         device_set_desc(dev, "VIA VT8233 (pre)");
  626                         return 0;
  627                 case VIA8233_REV_ID_8233C:
  628                         device_set_desc(dev, "VIA VT8233C");
  629                         return 0;
  630                 case VIA8233_REV_ID_8233:
  631                         device_set_desc(dev, "VIA VT8233");
  632                         return 0;
  633                 case VIA8233_REV_ID_8233A:
  634                         device_set_desc(dev, "VIA VT8233A");
  635                         return 0;
  636                 case VIA8233_REV_ID_8235:
  637                         device_set_desc(dev, "VIA VT8235");
  638                         return 0;
  639                 case VIA8233_REV_ID_8237:
  640                         device_set_desc(dev, "VIA VT8237");
  641                         return 0;
  642                 default:
  643                         device_set_desc(dev, "VIA VT8233X");    /* Unknown */
  644                         return 0;
  645                 }                       
  646         }
  647         return ENXIO;
  648 }
  649 
  650 static void
  651 dma_cb(void *p, bus_dma_segment_t *bds, int a, int b)
  652 {
  653         struct via_info *via = (struct via_info *)p;
  654         via->sgd_addr = bds->ds_addr;
  655 }
  656 
  657 static int
  658 via_chip_init(device_t dev)
  659 {
  660         u_int32_t data, cnt;
  661 
  662         /* Wake up and reset AC97 if necessary */
  663         data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
  664 
  665         if ((data & VIA_PCI_ACLINK_C00_READY) == 0) {
  666                 /* Cold reset per ac97r2.3 spec (page 95) */
  667                 /* Assert low */
  668                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 
  669                                  VIA_PCI_ACLINK_EN, 1); 
  670                 /* Wait T_rst_low */
  671                 DELAY(100);                             
  672                 /* Assert high */
  673                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 
  674                                  VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_NRST, 1);
  675                 /* Wait T_rst2clk */
  676                 DELAY(5);
  677                 /* Assert low */
  678                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 
  679                                  VIA_PCI_ACLINK_EN, 1);
  680         } else {
  681                 /* Warm reset */
  682                 /* Force no sync */
  683                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 
  684                                  VIA_PCI_ACLINK_EN, 1);
  685                 DELAY(100);
  686                 /* Sync */
  687                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 
  688                                  VIA_PCI_ACLINK_EN | VIA_PCI_ACLINK_SYNC, 1);
  689                 /* Wait T_sync_high */
  690                 DELAY(5);
  691                 /* Force no sync */
  692                 pci_write_config(dev, VIA_PCI_ACLINK_CTRL, 
  693                                  VIA_PCI_ACLINK_EN, 1);
  694                 /* Wait T_sync2clk */
  695                 DELAY(5);
  696         }
  697 
  698         /* Power everything up */
  699         pci_write_config(dev, VIA_PCI_ACLINK_CTRL, VIA_PCI_ACLINK_DESIRED, 1);
  700 
  701         /* Wait for codec to become ready (largest reported delay 310ms) */
  702         for (cnt = 0; cnt < 2000; cnt++) {
  703                 data = pci_read_config(dev, VIA_PCI_ACLINK_STAT, 1);
  704                 if (data & VIA_PCI_ACLINK_C00_READY) {
  705                         return 0;
  706                 }
  707                 DELAY(5000);
  708         }
  709         device_printf(dev, "primary codec not ready (cnt = 0x%02x)\n", cnt);
  710         return ENXIO;
  711 }
  712 
  713 #ifdef SND_DYNSYSCTL
  714 static int via8233_spdif_en;
  715 
  716 static int
  717 sysctl_via8233_spdif_enable(SYSCTL_HANDLER_ARGS)
  718 {
  719         device_t dev;
  720         int err, new_en, r;
  721 
  722         new_en = via8233_spdif_en;
  723         err = sysctl_handle_int(oidp, &new_en, sizeof(new_en), req);
  724         if (err || req->newptr == NULL)
  725                 return err;
  726 
  727         if (new_en < 0 || new_en > 1)
  728                 return EINVAL;
  729         via8233_spdif_en = new_en;
  730 
  731         dev = oidp->oid_arg1;
  732         r = pci_read_config(dev, VIA_PCI_SPDIF, 1) & ~VIA_SPDIF_EN;
  733         if (new_en)
  734                 r |= VIA_SPDIF_EN;
  735         pci_write_config(dev, VIA_PCI_SPDIF, r, 1);
  736         return 0;
  737 }
  738 #endif /* SND_DYNSYSCTL */
  739 
  740 static void
  741 via_init_sysctls(device_t dev)
  742 {
  743 #ifdef SND_DYNSYSCTL
  744         int r;
  745 
  746         r = pci_read_config(dev, VIA_PCI_SPDIF, 1);
  747         via8233_spdif_en = (r & VIA_SPDIF_EN) ? 1 : 0;
  748 
  749         SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
  750                         SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
  751                         OID_AUTO, "spdif_enabled", 
  752                         CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
  753                         sysctl_via8233_spdif_enable, "I",
  754                         "Enable S/PDIF output on primary playback channel");
  755 #endif
  756 }
  757 
  758 static int
  759 via_attach(device_t dev)
  760 {
  761         struct via_info *via = 0;
  762         char status[SND_STATUSLEN];
  763 
  764         if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
  765                 device_printf(dev, "cannot allocate softc\n");
  766                 return ENXIO;
  767         }
  768 
  769         pci_set_powerstate(dev, PCI_POWERSTATE_D0);
  770         pci_enable_busmaster(dev);
  771         
  772         via->regid = PCIR_BAR(0);
  773         via->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &via->regid,
  774                                           RF_ACTIVE);
  775         if (!via->reg) {
  776                 device_printf(dev, "cannot allocate bus resource.");
  777                 goto bad;
  778         }
  779         via->st = rman_get_bustag(via->reg);
  780         via->sh = rman_get_bushandle(via->reg);
  781 
  782         via->bufsz = pcm_getbuffersize(dev, 4096, VIA_DEFAULT_BUFSZ, 65536);
  783 
  784         via->irqid = 0;
  785         via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
  786                                           RF_ACTIVE | RF_SHAREABLE);
  787         if (!via->irq || 
  788             snd_setup_intr(dev, via->irq, 0, via_intr, via, &via->ih)) {
  789                 device_printf(dev, "unable to map interrupt\n");
  790                 goto bad;
  791         }
  792 
  793         /* DMA tag for buffers */
  794         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  795                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  796                 /*highaddr*/BUS_SPACE_MAXADDR,
  797                 /*filter*/NULL, /*filterarg*/NULL,
  798                 /*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
  799                 /*flags*/0, /*lockfunc*/busdma_lock_mutex,
  800                 /*lockarg*/&Giant, &via->parent_dmat) != 0) {
  801                 device_printf(dev, "unable to create dma tag\n");
  802                 goto bad;
  803         }
  804 
  805         /*
  806          *  DMA tag for SGD table.  The 686 uses scatter/gather DMA and
  807          *  requires a list in memory of work to do.  We need only 16 bytes
  808          *  for this list, and it is wasteful to allocate 16K.
  809          */
  810         if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
  811                 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  812                 /*highaddr*/BUS_SPACE_MAXADDR,
  813                 /*filter*/NULL, /*filterarg*/NULL,
  814                 /*maxsize*/NSEGS * sizeof(struct via_dma_op),
  815                 /*nsegments*/1, /*maxsegz*/0x3ffff,
  816                 /*flags*/0, /*lockfunc*/busdma_lock_mutex,
  817                 /*lockarg*/&Giant, &via->sgd_dmat) != 0) {
  818                 device_printf(dev, "unable to create dma tag\n");
  819                 goto bad;
  820         }
  821 
  822         if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, 
  823                              BUS_DMA_NOWAIT, &via->sgd_dmamap) == -1)
  824                 goto bad;
  825         if (bus_dmamap_load(via->sgd_dmat, via->sgd_dmamap, via->sgd_table, 
  826                             NSEGS * sizeof(struct via_dma_op), dma_cb, via, 0))
  827                 goto bad;
  828 
  829         if (via_chip_init(dev))
  830                 goto bad;
  831 
  832         via->codec = AC97_CREATE(dev, via, via_ac97);
  833         if (!via->codec)
  834                 goto bad;
  835 
  836         mixer_init(dev, ac97_getmixerclass(), via->codec);
  837 
  838         via->codec_caps = ac97_getextcaps(via->codec);
  839 
  840         /* Try to set VRA without generating an error, VRM not reqrd yet */
  841         if (via->codec_caps & 
  842             (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM | AC97_EXTCAP_DRA)) {
  843                 u_int16_t ext = ac97_getextmode(via->codec);
  844                 ext |= (via->codec_caps & 
  845                         (AC97_EXTCAP_VRA | AC97_EXTCAP_VRM));
  846                 ext &= ~AC97_EXTCAP_DRA;
  847                 ac97_setextmode(via->codec, ext);
  848         }
  849 
  850         snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s", 
  851                  rman_get_start(via->reg), rman_get_start(via->irq),PCM_KLDSTRING(snd_via8233));
  852 
  853         /* Register */
  854         if (pci_get_revid(dev) == VIA8233_REV_ID_8233A) {
  855                 if (pcm_register(dev, via, NMSGDCHANS, 1)) goto bad;
  856                 /*
  857                  * DXS channel is disabled.  Reports from multiple users
  858                  * that it plays at half-speed.  Do not see this behaviour
  859                  * on available 8233C or when emulating 8233A register set
  860                  * on 8233C (either with or without ac97 VRA).
  861                 pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
  862                  */
  863                 pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
  864                 pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
  865         } else {
  866                 int i;
  867                 if (pcm_register(dev, via, NMSGDCHANS + NDXSCHANS, NWRCHANS)) goto bad;
  868                 for (i = 0; i < NDXSCHANS; i++)
  869                         pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
  870                 pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
  871                 for (i = 0; i < NWRCHANS; i++)
  872                         pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
  873                 via_init_sysctls(dev);
  874         }
  875 
  876         pcm_setstatus(dev, status);
  877 
  878         return 0;
  879 bad:
  880         if (via->codec) ac97_destroy(via->codec);
  881         if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
  882         if (via->ih) bus_teardown_intr(dev, via->irq, via->ih);
  883         if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
  884         if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
  885         if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
  886         if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
  887         if (via) free(via, M_DEVBUF);
  888         return ENXIO;
  889 }
  890 
  891 static int
  892 via_detach(device_t dev)
  893 {
  894         int r;
  895         struct via_info *via = 0;
  896 
  897         r = pcm_unregister(dev);
  898         if (r) return r;
  899 
  900         via = pcm_getdevinfo(dev);
  901         bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg);
  902         bus_teardown_intr(dev, via->irq, via->ih);
  903         bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq);
  904         bus_dma_tag_destroy(via->parent_dmat);
  905         bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
  906         bus_dma_tag_destroy(via->sgd_dmat);
  907         free(via, M_DEVBUF);
  908         return 0;
  909 }
  910 
  911 
  912 static device_method_t via_methods[] = {
  913         DEVMETHOD(device_probe,         via_probe),
  914         DEVMETHOD(device_attach,        via_attach),
  915         DEVMETHOD(device_detach,        via_detach),
  916         { 0, 0}
  917 };
  918 
  919 static driver_t via_driver = {
  920         "pcm",
  921         via_methods,
  922         PCM_SOFTC_SIZE,
  923 };
  924 
  925 DRIVER_MODULE(snd_via8233, pci, via_driver, pcm_devclass, 0, 0);
  926 MODULE_DEPEND(snd_via8233, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
  927 MODULE_VERSION(snd_via8233, 1);

Cache object: a4ec56d5cd32500d0db25cda2f77edcd


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