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/csapcm.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) 1999 Seigo Tanimura
    5  * All rights reserved.
    6  *
    7  * Portions of this source are based on cwcealdr.cpp and dhwiface.cpp in
    8  * cwcealdr1.zip, the sample sources by Crystal Semiconductor.
    9  * Copyright (c) 1996-1998 Crystal Semiconductor Corp.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  */
   32 
   33 #ifdef HAVE_KERNEL_OPTION_HEADERS
   34 #include "opt_snd.h"
   35 #endif
   36 
   37 #include <dev/sound/pcm/sound.h>
   38 #include <dev/sound/pcm/ac97.h>
   39 #include <dev/sound/chip.h>
   40 #include <dev/sound/pci/csareg.h>
   41 #include <dev/sound/pci/csavar.h>
   42 
   43 #include <dev/pci/pcireg.h>
   44 #include <dev/pci/pcivar.h>
   45 
   46 SND_DECLARE_FILE("$FreeBSD$");
   47 
   48 /* Buffer size on dma transfer. Fixed for CS416x. */
   49 #define CS461x_BUFFSIZE   (4 * 1024)
   50 
   51 #define GOF_PER_SEC 200
   52 
   53 /* device private data */
   54 struct csa_info;
   55 
   56 struct csa_chinfo {
   57         struct csa_info *parent;
   58         struct pcm_channel *channel;
   59         struct snd_dbuf *buffer;
   60         int dir;
   61         u_int32_t fmt, spd;
   62         int dma;
   63 };
   64 
   65 struct csa_info {
   66         csa_res         res; /* resource */
   67         void            *ih; /* Interrupt cookie */
   68         bus_dma_tag_t   parent_dmat; /* DMA tag */
   69         struct csa_bridgeinfo *binfo; /* The state of the parent. */
   70         struct csa_card *card;
   71 
   72         int active;
   73         /* Contents of board's registers */
   74         u_long          pfie;
   75         u_long          pctl;
   76         u_long          cctl;
   77         struct csa_chinfo pch, rch;
   78         u_int32_t       ac97[CS461x_AC97_NUMBER_RESTORE_REGS];
   79         u_int32_t       ac97_powerdown;
   80         u_int32_t       ac97_general_purpose;
   81 };
   82 
   83 /* -------------------------------------------------------------------- */
   84 
   85 /* prototypes */
   86 static int      csa_init(struct csa_info *);
   87 static void     csa_intr(void *);
   88 static void     csa_setplaysamplerate(csa_res *resp, u_long ulInRate);
   89 static void     csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate);
   90 static void     csa_startplaydma(struct csa_info *csa);
   91 static void     csa_startcapturedma(struct csa_info *csa);
   92 static void     csa_stopplaydma(struct csa_info *csa);
   93 static void     csa_stopcapturedma(struct csa_info *csa);
   94 static int      csa_startdsp(csa_res *resp);
   95 static int      csa_stopdsp(csa_res *resp);
   96 static int      csa_allocres(struct csa_info *scp, device_t dev);
   97 static void     csa_releaseres(struct csa_info *scp, device_t dev);
   98 static void     csa_ac97_suspend(struct csa_info *csa);
   99 static void     csa_ac97_resume(struct csa_info *csa);
  100 
  101 static u_int32_t csa_playfmt[] = {
  102         SND_FORMAT(AFMT_U8, 1, 0),
  103         SND_FORMAT(AFMT_U8, 2, 0),
  104         SND_FORMAT(AFMT_S8, 1, 0),
  105         SND_FORMAT(AFMT_S8, 2, 0),
  106         SND_FORMAT(AFMT_S16_LE, 1, 0),
  107         SND_FORMAT(AFMT_S16_LE, 2, 0),
  108         SND_FORMAT(AFMT_S16_BE, 1, 0),
  109         SND_FORMAT(AFMT_S16_BE, 2, 0),
  110         0
  111 };
  112 static struct pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0};
  113 
  114 static u_int32_t csa_recfmt[] = {
  115         SND_FORMAT(AFMT_S16_LE, 1, 0),
  116         SND_FORMAT(AFMT_S16_LE, 2, 0),
  117         0
  118 };
  119 static struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0};
  120 
  121 /* -------------------------------------------------------------------- */
  122 
  123 static int
  124 csa_active(struct csa_info *csa, int run)
  125 {
  126         int old;
  127 
  128         old = csa->active;
  129         csa->active += run;
  130 
  131         if ((csa->active > 1) || (csa->active < -1))
  132                 csa->active = 0;
  133         if (csa->card->active)
  134                 return (csa->card->active(!(csa->active && old)));
  135 
  136         return 0;
  137 }
  138 
  139 /* -------------------------------------------------------------------- */
  140 /* ac97 codec */
  141 
  142 static int
  143 csa_rdcd(kobj_t obj, void *devinfo, int regno)
  144 {
  145         u_int32_t data;
  146         struct csa_info *csa = (struct csa_info *)devinfo;
  147 
  148         csa_active(csa, 1);
  149         if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data))
  150                 data = 0;
  151         csa_active(csa, -1);
  152 
  153         return data;
  154 }
  155 
  156 static int
  157 csa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data)
  158 {
  159         struct csa_info *csa = (struct csa_info *)devinfo;
  160 
  161         csa_active(csa, 1);
  162         csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data);
  163         csa_active(csa, -1);
  164 
  165         return 0;
  166 }
  167 
  168 static kobj_method_t csa_ac97_methods[] = {
  169         KOBJMETHOD(ac97_read,           csa_rdcd),
  170         KOBJMETHOD(ac97_write,          csa_wrcd),
  171         KOBJMETHOD_END
  172 };
  173 AC97_DECLARE(csa_ac97);
  174 
  175 static void
  176 csa_setplaysamplerate(csa_res *resp, u_long ulInRate)
  177 {
  178         u_long ulTemp1, ulTemp2;
  179         u_long ulPhiIncr;
  180         u_long ulCorrectionPerGOF, ulCorrectionPerSec;
  181         u_long ulOutRate;
  182 
  183         ulOutRate = 48000;
  184 
  185         /*
  186          * Compute the values used to drive the actual sample rate conversion.
  187          * The following formulas are being computed, using inline assembly
  188          * since we need to use 64 bit arithmetic to compute the values:
  189          *
  190          *     ulPhiIncr = floor((Fs,in * 2^26) / Fs,out)
  191          *     ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) /
  192          *                                GOF_PER_SEC)
  193          *     ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
  194          *                          GOF_PER_SEC * ulCorrectionPerGOF
  195          *
  196          * i.e.
  197          *
  198          *     ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
  199          *     ulCorrectionPerGOF:ulCorrectionPerSec =
  200          *         dividend:remainder(ulOther / GOF_PER_SEC)
  201          */
  202         ulTemp1 = ulInRate << 16;
  203         ulPhiIncr = ulTemp1 / ulOutRate;
  204         ulTemp1 -= ulPhiIncr * ulOutRate;
  205         ulTemp1 <<= 10;
  206         ulPhiIncr <<= 10;
  207         ulTemp2 = ulTemp1 / ulOutRate;
  208         ulPhiIncr += ulTemp2;
  209         ulTemp1 -= ulTemp2 * ulOutRate;
  210         ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC;
  211         ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC;
  212         ulCorrectionPerSec = ulTemp1;
  213 
  214         /*
  215          * Fill in the SampleRateConverter control block.
  216          */
  217         csa_writemem(resp, BA1_PSRC, ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF));
  218         csa_writemem(resp, BA1_PPI, ulPhiIncr);
  219 }
  220 
  221 static void
  222 csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate)
  223 {
  224         u_long ulPhiIncr, ulCoeffIncr, ulTemp1, ulTemp2;
  225         u_long ulCorrectionPerGOF, ulCorrectionPerSec, ulInitialDelay;
  226         u_long dwFrameGroupLength, dwCnt;
  227         u_long ulInRate;
  228 
  229         ulInRate = 48000;
  230 
  231         /*
  232          * We can only decimate by up to a factor of 1/9th the hardware rate.
  233          * Return an error if an attempt is made to stray outside that limit.
  234          */
  235         if((ulOutRate * 9) < ulInRate)
  236                 return;
  237 
  238         /*
  239          * We can not capture at at rate greater than the Input Rate (48000).
  240          * Return an error if an attempt is made to stray outside that limit.
  241          */
  242         if(ulOutRate > ulInRate)
  243                 return;
  244 
  245         /*
  246          * Compute the values used to drive the actual sample rate conversion.
  247          * The following formulas are being computed, using inline assembly
  248          * since we need to use 64 bit arithmetic to compute the values:
  249          *
  250          *     ulCoeffIncr = -floor((Fs,out * 2^23) / Fs,in)
  251          *     ulPhiIncr = floor((Fs,in * 2^26) / Fs,out)
  252          *     ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) /
  253          *                                GOF_PER_SEC)
  254          *     ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
  255          *                          GOF_PER_SEC * ulCorrectionPerGOF
  256          *     ulInitialDelay = ceil((24 * Fs,in) / Fs,out)
  257          *
  258          * i.e.
  259          *
  260          *     ulCoeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))
  261          *     ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
  262          *     ulCorrectionPerGOF:ulCorrectionPerSec =
  263          *         dividend:remainder(ulOther / GOF_PER_SEC)
  264          *     ulInitialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
  265          */
  266         ulTemp1 = ulOutRate << 16;
  267         ulCoeffIncr = ulTemp1 / ulInRate;
  268         ulTemp1 -= ulCoeffIncr * ulInRate;
  269         ulTemp1 <<= 7;
  270         ulCoeffIncr <<= 7;
  271         ulCoeffIncr += ulTemp1 / ulInRate;
  272         ulCoeffIncr ^= 0xFFFFFFFF;
  273         ulCoeffIncr++;
  274         ulTemp1 = ulInRate << 16;
  275         ulPhiIncr = ulTemp1 / ulOutRate;
  276         ulTemp1 -= ulPhiIncr * ulOutRate;
  277         ulTemp1 <<= 10;
  278         ulPhiIncr <<= 10;
  279         ulTemp2 = ulTemp1 / ulOutRate;
  280         ulPhiIncr += ulTemp2;
  281         ulTemp1 -= ulTemp2 * ulOutRate;
  282         ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC;
  283         ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC;
  284         ulCorrectionPerSec = ulTemp1;
  285         ulInitialDelay = ((ulInRate * 24) + ulOutRate - 1) / ulOutRate;
  286 
  287         /*
  288          * Fill in the VariDecimate control block.
  289          */
  290         csa_writemem(resp, BA1_CSRC,
  291                      ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF));
  292         csa_writemem(resp, BA1_CCI, ulCoeffIncr);
  293         csa_writemem(resp, BA1_CD,
  294              (((BA1_VARIDEC_BUF_1 + (ulInitialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
  295         csa_writemem(resp, BA1_CPI, ulPhiIncr);
  296 
  297         /*
  298          * Figure out the frame group length for the write back task.  Basically,
  299          * this is just the factors of 24000 (2^6*3*5^3) that are not present in
  300          * the output sample rate.
  301          */
  302         dwFrameGroupLength = 1;
  303         for(dwCnt = 2; dwCnt <= 64; dwCnt *= 2)
  304         {
  305                 if(((ulOutRate / dwCnt) * dwCnt) !=
  306                    ulOutRate)
  307                 {
  308                         dwFrameGroupLength *= 2;
  309                 }
  310         }
  311         if(((ulOutRate / 3) * 3) !=
  312            ulOutRate)
  313         {
  314                 dwFrameGroupLength *= 3;
  315         }
  316         for(dwCnt = 5; dwCnt <= 125; dwCnt *= 5)
  317         {
  318                 if(((ulOutRate / dwCnt) * dwCnt) !=
  319                    ulOutRate)
  320                 {
  321                         dwFrameGroupLength *= 5;
  322                 }
  323         }
  324 
  325         /*
  326          * Fill in the WriteBack control block.
  327          */
  328         csa_writemem(resp, BA1_CFG1, dwFrameGroupLength);
  329         csa_writemem(resp, BA1_CFG2, (0x00800000 | dwFrameGroupLength));
  330         csa_writemem(resp, BA1_CCST, 0x0000FFFF);
  331         csa_writemem(resp, BA1_CSPB, ((65536 * ulOutRate) / 24000));
  332         csa_writemem(resp, (BA1_CSPB + 4), 0x0000FFFF);
  333 }
  334 
  335 static void
  336 csa_startplaydma(struct csa_info *csa)
  337 {
  338         csa_res *resp;
  339         u_long ul;
  340 
  341         if (!csa->pch.dma) {
  342                 resp = &csa->res;
  343                 ul = csa_readmem(resp, BA1_PCTL);
  344                 ul &= 0x0000ffff;
  345                 csa_writemem(resp, BA1_PCTL, ul | csa->pctl);
  346                 csa_writemem(resp, BA1_PVOL, 0x80008000);
  347                 csa->pch.dma = 1;
  348         }
  349 }
  350 
  351 static void
  352 csa_startcapturedma(struct csa_info *csa)
  353 {
  354         csa_res *resp;
  355         u_long ul;
  356 
  357         if (!csa->rch.dma) {
  358                 resp = &csa->res;
  359                 ul = csa_readmem(resp, BA1_CCTL);
  360                 ul &= 0xffff0000;
  361                 csa_writemem(resp, BA1_CCTL, ul | csa->cctl);
  362                 csa_writemem(resp, BA1_CVOL, 0x80008000);
  363                 csa->rch.dma = 1;
  364         }
  365 }
  366 
  367 static void
  368 csa_stopplaydma(struct csa_info *csa)
  369 {
  370         csa_res *resp;
  371         u_long ul;
  372 
  373         if (csa->pch.dma) {
  374                 resp = &csa->res;
  375                 ul = csa_readmem(resp, BA1_PCTL);
  376                 csa->pctl = ul & 0xffff0000;
  377                 csa_writemem(resp, BA1_PCTL, ul & 0x0000ffff);
  378                 csa_writemem(resp, BA1_PVOL, 0xffffffff);
  379                 csa->pch.dma = 0;
  380 
  381                 /*
  382                  * The bitwise pointer of the serial FIFO in the DSP
  383                  * seems to make an error upon starting or stopping the
  384                  * DSP. Clear the FIFO and correct the pointer if we
  385                  * are not capturing.
  386                  */
  387                 if (!csa->rch.dma) {
  388                         csa_clearserialfifos(resp);
  389                         csa_writeio(resp, BA0_SERBSP, 0);
  390                 }
  391         }
  392 }
  393 
  394 static void
  395 csa_stopcapturedma(struct csa_info *csa)
  396 {
  397         csa_res *resp;
  398         u_long ul;
  399 
  400         if (csa->rch.dma) {
  401                 resp = &csa->res;
  402                 ul = csa_readmem(resp, BA1_CCTL);
  403                 csa->cctl = ul & 0x0000ffff;
  404                 csa_writemem(resp, BA1_CCTL, ul & 0xffff0000);
  405                 csa_writemem(resp, BA1_CVOL, 0xffffffff);
  406                 csa->rch.dma = 0;
  407 
  408                 /*
  409                  * The bitwise pointer of the serial FIFO in the DSP
  410                  * seems to make an error upon starting or stopping the
  411                  * DSP. Clear the FIFO and correct the pointer if we
  412                  * are not playing.
  413                  */
  414                 if (!csa->pch.dma) {
  415                         csa_clearserialfifos(resp);
  416                         csa_writeio(resp, BA0_SERBSP, 0);
  417                 }
  418         }
  419 }
  420 
  421 static int
  422 csa_startdsp(csa_res *resp)
  423 {
  424         int i;
  425         u_long ul;
  426 
  427         /*
  428          * Set the frame timer to reflect the number of cycles per frame.
  429          */
  430         csa_writemem(resp, BA1_FRMT, 0xadf);
  431 
  432         /*
  433          * Turn on the run, run at frame, and DMA enable bits in the local copy of
  434          * the SP control register.
  435          */
  436         csa_writemem(resp, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
  437 
  438         /*
  439          * Wait until the run at frame bit resets itself in the SP control
  440          * register.
  441          */
  442         ul = 0;
  443         for (i = 0 ; i < 25 ; i++) {
  444                 /*
  445                  * Wait a little bit, so we don't issue PCI reads too frequently.
  446                  */
  447                 DELAY(50);
  448                 /*
  449                  * Fetch the current value of the SP status register.
  450                  */
  451                 ul = csa_readmem(resp, BA1_SPCR);
  452 
  453                 /*
  454                  * If the run at frame bit has reset, then stop waiting.
  455                  */
  456                 if((ul & SPCR_RUNFR) == 0)
  457                         break;
  458         }
  459         /*
  460          * If the run at frame bit never reset, then return an error.
  461          */
  462         if((ul & SPCR_RUNFR) != 0)
  463                 return (EAGAIN);
  464 
  465         return (0);
  466 }
  467 
  468 static int
  469 csa_stopdsp(csa_res *resp)
  470 {
  471         /*
  472          * Turn off the run, run at frame, and DMA enable bits in
  473          * the local copy of the SP control register.
  474          */
  475         csa_writemem(resp, BA1_SPCR, 0);
  476 
  477         return (0);
  478 }
  479 
  480 static int
  481 csa_setupchan(struct csa_chinfo *ch)
  482 {
  483         struct csa_info *csa = ch->parent;
  484         csa_res *resp = &csa->res;
  485         u_long pdtc, tmp;
  486 
  487         if (ch->dir == PCMDIR_PLAY) {
  488                 /* direction */
  489                 csa_writemem(resp, BA1_PBA, sndbuf_getbufaddr(ch->buffer));
  490 
  491                 /* format */
  492                 csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f;
  493                 if (!(ch->fmt & AFMT_SIGNED))
  494                         csa->pfie |= 0x8000;
  495                 if (ch->fmt & AFMT_BIGENDIAN)
  496                         csa->pfie |= 0x4000;
  497                 if (AFMT_CHANNEL(ch->fmt) < 2)
  498                         csa->pfie |= 0x2000;
  499                 if (ch->fmt & AFMT_8BIT)
  500                         csa->pfie |= 0x1000;
  501                 csa_writemem(resp, BA1_PFIE, csa->pfie);
  502 
  503                 tmp = 4;
  504                 if (ch->fmt & AFMT_16BIT)
  505                         tmp <<= 1;
  506                 if (AFMT_CHANNEL(ch->fmt) > 1)
  507                         tmp <<= 1;
  508                 tmp--;
  509 
  510                 pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000001ff;
  511                 pdtc |= tmp;
  512                 csa_writemem(resp, BA1_PDTC, pdtc);
  513 
  514                 /* rate */
  515                 csa_setplaysamplerate(resp, ch->spd);
  516         } else if (ch->dir == PCMDIR_REC) {
  517                 /* direction */
  518                 csa_writemem(resp, BA1_CBA, sndbuf_getbufaddr(ch->buffer));
  519 
  520                 /* format */
  521                 csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
  522 
  523                 /* rate */
  524                 csa_setcapturesamplerate(resp, ch->spd);
  525         }
  526         return 0;
  527 }
  528 
  529 /* -------------------------------------------------------------------- */
  530 /* channel interface */
  531 
  532 static void *
  533 csachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
  534 {
  535         struct csa_info *csa = devinfo;
  536         struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch;
  537 
  538         ch->parent = csa;
  539         ch->channel = c;
  540         ch->buffer = b;
  541         ch->dir = dir;
  542         if (sndbuf_alloc(ch->buffer, csa->parent_dmat, 0, CS461x_BUFFSIZE) != 0)
  543                 return NULL;
  544         return ch;
  545 }
  546 
  547 static int
  548 csachan_setformat(kobj_t obj, void *data, u_int32_t format)
  549 {
  550         struct csa_chinfo *ch = data;
  551 
  552         ch->fmt = format;
  553         return 0;
  554 }
  555 
  556 static u_int32_t
  557 csachan_setspeed(kobj_t obj, void *data, u_int32_t speed)
  558 {
  559         struct csa_chinfo *ch = data;
  560 
  561         ch->spd = speed;
  562         return ch->spd; /* XXX calc real speed */
  563 }
  564 
  565 static u_int32_t
  566 csachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
  567 {
  568         return CS461x_BUFFSIZE / 2;
  569 }
  570 
  571 static int
  572 csachan_trigger(kobj_t obj, void *data, int go)
  573 {
  574         struct csa_chinfo *ch = data;
  575         struct csa_info *csa = ch->parent;
  576 
  577         if (!PCMTRIG_COMMON(go))
  578                 return 0;
  579 
  580         if (go == PCMTRIG_START) {
  581                 csa_active(csa, 1);
  582                 csa_setupchan(ch);
  583                 if (ch->dir == PCMDIR_PLAY)
  584                         csa_startplaydma(csa);
  585                 else
  586                         csa_startcapturedma(csa);
  587         } else {
  588                 if (ch->dir == PCMDIR_PLAY)
  589                         csa_stopplaydma(csa);
  590                 else
  591                         csa_stopcapturedma(csa);
  592                 csa_active(csa, -1);
  593         }
  594         return 0;
  595 }
  596 
  597 static u_int32_t
  598 csachan_getptr(kobj_t obj, void *data)
  599 {
  600         struct csa_chinfo *ch = data;
  601         struct csa_info *csa = ch->parent;
  602         csa_res *resp;
  603         u_int32_t ptr;
  604 
  605         resp = &csa->res;
  606 
  607         if (ch->dir == PCMDIR_PLAY) {
  608                 ptr = csa_readmem(resp, BA1_PBA) - sndbuf_getbufaddr(ch->buffer);
  609                 if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0)
  610                         ptr >>= 1;
  611         } else {
  612                 ptr = csa_readmem(resp, BA1_CBA) - sndbuf_getbufaddr(ch->buffer);
  613                 if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0)
  614                         ptr >>= 1;
  615         }
  616 
  617         return (ptr);
  618 }
  619 
  620 static struct pcmchan_caps *
  621 csachan_getcaps(kobj_t obj, void *data)
  622 {
  623         struct csa_chinfo *ch = data;
  624         return (ch->dir == PCMDIR_PLAY)? &csa_playcaps : &csa_reccaps;
  625 }
  626 
  627 static kobj_method_t csachan_methods[] = {
  628         KOBJMETHOD(channel_init,                csachan_init),
  629         KOBJMETHOD(channel_setformat,           csachan_setformat),
  630         KOBJMETHOD(channel_setspeed,            csachan_setspeed),
  631         KOBJMETHOD(channel_setblocksize,        csachan_setblocksize),
  632         KOBJMETHOD(channel_trigger,             csachan_trigger),
  633         KOBJMETHOD(channel_getptr,              csachan_getptr),
  634         KOBJMETHOD(channel_getcaps,             csachan_getcaps),
  635         KOBJMETHOD_END
  636 };
  637 CHANNEL_DECLARE(csachan);
  638 
  639 /* -------------------------------------------------------------------- */
  640 /* The interrupt handler */
  641 static void
  642 csa_intr(void *p)
  643 {
  644         struct csa_info *csa = p;
  645 
  646         if ((csa->binfo->hisr & HISR_VC0) != 0)
  647                 chn_intr(csa->pch.channel);
  648         if ((csa->binfo->hisr & HISR_VC1) != 0)
  649                 chn_intr(csa->rch.channel);
  650 }
  651 
  652 /* -------------------------------------------------------------------- */
  653 
  654 /*
  655  * Probe and attach the card
  656  */
  657 
  658 static int
  659 csa_init(struct csa_info *csa)
  660 {
  661         csa_res *resp;
  662 
  663         resp = &csa->res;
  664 
  665         csa->pfie = 0;
  666         csa_stopplaydma(csa);
  667         csa_stopcapturedma(csa);
  668 
  669         if (csa_startdsp(resp))
  670                 return (1);
  671 
  672         /* Crank up the power on the DAC and ADC. */
  673         csa_setplaysamplerate(resp, 8000);
  674         csa_setcapturesamplerate(resp, 8000);
  675         /* Set defaults */
  676         csa_writeio(resp, BA0_EGPIODR, EGPIODR_GPOE0);
  677         csa_writeio(resp, BA0_EGPIOPTR, EGPIOPTR_GPPT0);
  678         /* Power up amplifier */
  679         csa_writeio(resp, BA0_EGPIODR, csa_readio(resp, BA0_EGPIODR) |
  680                 EGPIODR_GPOE2);
  681         csa_writeio(resp, BA0_EGPIOPTR, csa_readio(resp, BA0_EGPIOPTR) | 
  682                 EGPIOPTR_GPPT2);
  683 
  684         return 0;
  685 }
  686 
  687 /* Allocates resources. */
  688 static int
  689 csa_allocres(struct csa_info *csa, device_t dev)
  690 {
  691         csa_res *resp;
  692 
  693         resp = &csa->res;
  694         if (resp->io == NULL) {
  695                 resp->io = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  696                         &resp->io_rid, RF_ACTIVE);
  697                 if (resp->io == NULL)
  698                         return (1);
  699         }
  700         if (resp->mem == NULL) {
  701                 resp->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  702                         &resp->mem_rid, RF_ACTIVE);
  703                 if (resp->mem == NULL)
  704                         return (1);
  705         }
  706         if (resp->irq == NULL) {
  707                 resp->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  708                         &resp->irq_rid, RF_ACTIVE | RF_SHAREABLE);
  709                 if (resp->irq == NULL)
  710                         return (1);
  711         }
  712         if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev),
  713                                /*alignment*/CS461x_BUFFSIZE,
  714                                /*boundary*/CS461x_BUFFSIZE,
  715                                /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
  716                                /*highaddr*/BUS_SPACE_MAXADDR,
  717                                /*filter*/NULL, /*filterarg*/NULL,
  718                                /*maxsize*/CS461x_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff,
  719                                /*flags*/0, /*lockfunc*/NULL, /*lockarg*/NULL,
  720                                &csa->parent_dmat) != 0)
  721                 return (1);
  722 
  723         return (0);
  724 }
  725 
  726 /* Releases resources. */
  727 static void
  728 csa_releaseres(struct csa_info *csa, device_t dev)
  729 {
  730         csa_res *resp;
  731 
  732         KASSERT(csa != NULL, ("called with bogus resource structure"));
  733 
  734         resp = &csa->res;
  735         if (resp->irq != NULL) {
  736                 if (csa->ih)
  737                         bus_teardown_intr(dev, resp->irq, csa->ih);
  738                 bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq);
  739                 resp->irq = NULL;
  740         }
  741         if (resp->io != NULL) {
  742                 bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io);
  743                 resp->io = NULL;
  744         }
  745         if (resp->mem != NULL) {
  746                 bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem);
  747                 resp->mem = NULL;
  748         }
  749         if (csa->parent_dmat != NULL) {
  750                 bus_dma_tag_destroy(csa->parent_dmat);
  751                 csa->parent_dmat = NULL;
  752         }
  753 
  754         free(csa, M_DEVBUF);
  755 }
  756 
  757 static int
  758 pcmcsa_probe(device_t dev)
  759 {
  760         char *s;
  761         struct sndcard_func *func;
  762 
  763         /* The parent device has already been probed. */
  764 
  765         func = device_get_ivars(dev);
  766         if (func == NULL || func->func != SCF_PCM)
  767                 return (ENXIO);
  768 
  769         s = "CS461x PCM Audio";
  770 
  771         device_set_desc(dev, s);
  772         return (0);
  773 }
  774 
  775 static int
  776 pcmcsa_attach(device_t dev)
  777 {
  778         struct csa_info *csa;
  779         csa_res *resp;
  780         char status[SND_STATUSLEN];
  781         struct ac97_info *codec;
  782         struct sndcard_func *func;
  783 
  784         csa = malloc(sizeof(*csa), M_DEVBUF, M_WAITOK | M_ZERO);
  785         func = device_get_ivars(dev);
  786         csa->binfo = func->varinfo;
  787         /*
  788          * Fake the status of DMA so that the initial value of
  789          * PCTL and CCTL can be stored into csa->pctl and csa->cctl,
  790          * respectively.
  791          */
  792         csa->pch.dma = csa->rch.dma = 1;
  793         csa->active = 0;
  794         csa->card = csa->binfo->card;
  795 
  796         /* Allocate the resources. */
  797         resp = &csa->res;
  798         resp->io_rid = PCIR_BAR(0);
  799         resp->mem_rid = PCIR_BAR(1);
  800         resp->irq_rid = 0;
  801         if (csa_allocres(csa, dev)) {
  802                 csa_releaseres(csa, dev);
  803                 return (ENXIO);
  804         }
  805 
  806         csa_active(csa, 1);
  807         if (csa_init(csa)) {
  808                 csa_releaseres(csa, dev);
  809                 return (ENXIO);
  810         }
  811         codec = AC97_CREATE(dev, csa, csa_ac97);
  812         if (codec == NULL) {
  813                 csa_releaseres(csa, dev);
  814                 return (ENXIO);
  815         }
  816         if (csa->card->inv_eapd)
  817                 ac97_setflags(codec, AC97_F_EAPD_INV);
  818         if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) {
  819                 ac97_destroy(codec);
  820                 csa_releaseres(csa, dev);
  821                 return (ENXIO);
  822         }
  823 
  824         snprintf(status, SND_STATUSLEN, "at irq %jd %s",
  825                         rman_get_start(resp->irq),PCM_KLDSTRING(snd_csa));
  826 
  827         /* Enable interrupt. */
  828         if (snd_setup_intr(dev, resp->irq, 0, csa_intr, csa, &csa->ih)) {
  829                 ac97_destroy(codec);
  830                 csa_releaseres(csa, dev);
  831                 return (ENXIO);
  832         }
  833         csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f);
  834         csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
  835         csa_active(csa, -1);
  836 
  837         if (pcm_register(dev, csa, 1, 1)) {
  838                 ac97_destroy(codec);
  839                 csa_releaseres(csa, dev);
  840                 return (ENXIO);
  841         }
  842         pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa);
  843         pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa);
  844         pcm_setstatus(dev, status);
  845 
  846         return (0);
  847 }
  848 
  849 static int
  850 pcmcsa_detach(device_t dev)
  851 {
  852         int r;
  853         struct csa_info *csa;
  854 
  855         r = pcm_unregister(dev);
  856         if (r)
  857                 return r;
  858 
  859         csa = pcm_getdevinfo(dev);
  860         csa_releaseres(csa, dev);
  861 
  862         return 0;
  863 }
  864 
  865 static void
  866 csa_ac97_suspend(struct csa_info *csa)
  867 {
  868         int count, i;
  869         uint32_t tmp;
  870 
  871         for (count = 0x2, i=0;
  872             (count <= CS461x_AC97_HIGHESTREGTORESTORE) &&
  873             (i < CS461x_AC97_NUMBER_RESTORE_REGS);
  874             count += 2, i++)
  875                 csa_readcodec(&csa->res, BA0_AC97_RESET + count, &csa->ac97[i]);
  876 
  877         /* mute the outputs */
  878         csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME, 0x8000);
  879         csa_writecodec(&csa->res, BA0_AC97_HEADPHONE_VOLUME, 0x8000);
  880         csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
  881         csa_writecodec(&csa->res, BA0_AC97_PCM_OUT_VOLUME, 0x8000);
  882         /* save the registers that cause pops */
  883         csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &csa->ac97_powerdown);
  884         csa_readcodec(&csa->res, BA0_AC97_GENERAL_PURPOSE,
  885             &csa->ac97_general_purpose);
  886 
  887         /*
  888          * And power down everything on the AC97 codec. Well, for now,
  889          * only power down the DAC/ADC and MIXER VREFON components.
  890          * trouble with removing VREF.
  891          */
  892 
  893         /* MIXVON */
  894         csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp);
  895         csa_writecodec(&csa->res, BA0_AC97_POWERDOWN,
  896             tmp | CS_AC97_POWER_CONTROL_MIXVON);
  897         /* ADC */
  898         csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp);
  899         csa_writecodec(&csa->res, BA0_AC97_POWERDOWN,
  900             tmp | CS_AC97_POWER_CONTROL_ADC);
  901         /* DAC */
  902         csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp);
  903         csa_writecodec(&csa->res, BA0_AC97_POWERDOWN,
  904             tmp | CS_AC97_POWER_CONTROL_DAC);
  905 }
  906 
  907 static void
  908 csa_ac97_resume(struct csa_info *csa)
  909 {
  910         int count, i;
  911 
  912         /*
  913          * First, we restore the state of the general purpose register.  This
  914          * contains the mic select (mic1 or mic2) and if we restore this after
  915          * we restore the mic volume/boost state and mic2 was selected at
  916          * suspend time, we will end up with a brief period of time where mic1
  917          * is selected with the volume/boost settings for mic2, causing
  918          * acoustic feedback.  So we restore the general purpose register
  919          * first, thereby getting the correct mic selected before we restore
  920          * the mic volume/boost.
  921          */
  922         csa_writecodec(&csa->res, BA0_AC97_GENERAL_PURPOSE,
  923             csa->ac97_general_purpose);
  924         /*
  925          * Now, while the outputs are still muted, restore the state of power
  926          * on the AC97 part.
  927          */
  928         csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, csa->ac97_powerdown);
  929         /*
  930          * Restore just the first set of registers, from register number
  931          * 0x02 to the register number that ulHighestRegToRestore specifies.
  932          */
  933         for (count = 0x2, i=0;
  934             (count <= CS461x_AC97_HIGHESTREGTORESTORE) &&
  935             (i < CS461x_AC97_NUMBER_RESTORE_REGS);
  936             count += 2, i++)
  937                 csa_writecodec(&csa->res, BA0_AC97_RESET + count, csa->ac97[i]);
  938 }
  939 
  940 static int
  941 pcmcsa_suspend(device_t dev)
  942 {
  943         struct csa_info *csa;
  944         csa_res *resp;
  945 
  946         csa = pcm_getdevinfo(dev);
  947         resp = &csa->res;
  948 
  949         csa_active(csa, 1);
  950 
  951         /* playback interrupt disable */
  952         csa_writemem(resp, BA1_PFIE,
  953             (csa_readmem(resp, BA1_PFIE) & ~0x0000f03f) | 0x00000010);
  954         /* capture interrupt disable */
  955         csa_writemem(resp, BA1_CIE,
  956             (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000011);
  957         csa_stopplaydma(csa);
  958         csa_stopcapturedma(csa);
  959 
  960         csa_ac97_suspend(csa);
  961 
  962         csa_resetdsp(resp);
  963 
  964         csa_stopdsp(resp);
  965         /*
  966          *  Power down the DAC and ADC.  For now leave the other areas on.
  967          */
  968         csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 0x300);
  969         /*
  970          *  Power down the PLL.
  971          */
  972         csa_writemem(resp, BA0_CLKCR1, 0);
  973         /*
  974          * Turn off the Processor by turning off the software clock
  975          * enable flag in the clock control register.
  976          */
  977         csa_writemem(resp, BA0_CLKCR1,
  978             csa_readmem(resp, BA0_CLKCR1) & ~CLKCR1_SWCE);
  979 
  980         csa_active(csa, -1);
  981 
  982         return 0;
  983 }
  984 
  985 static int
  986 pcmcsa_resume(device_t dev)
  987 {
  988         struct csa_info *csa;
  989         csa_res *resp;
  990 
  991         csa = pcm_getdevinfo(dev);
  992         resp = &csa->res;
  993 
  994         csa_active(csa, 1);
  995 
  996         /* cs_hardware_init */
  997         csa_stopplaydma(csa);
  998         csa_stopcapturedma(csa);
  999         csa_ac97_resume(csa);
 1000         if (csa_startdsp(resp))
 1001                 return (ENXIO);
 1002         /* Enable interrupts on the part. */
 1003         if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0)
 1004                 csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM);
 1005         /* playback interrupt enable */
 1006         csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f);
 1007         /* capture interrupt enable */
 1008         csa_writemem(resp, BA1_CIE,
 1009             (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
 1010         /* cs_restart_part */
 1011         csa_setupchan(&csa->pch);
 1012         csa_startplaydma(csa);
 1013         csa_setupchan(&csa->rch);
 1014         csa_startcapturedma(csa);
 1015 
 1016         csa_active(csa, -1);
 1017 
 1018         return 0;
 1019 }
 1020 
 1021 static device_method_t pcmcsa_methods[] = {
 1022         /* Device interface */
 1023         DEVMETHOD(device_probe , pcmcsa_probe ),
 1024         DEVMETHOD(device_attach, pcmcsa_attach),
 1025         DEVMETHOD(device_detach, pcmcsa_detach),
 1026         DEVMETHOD(device_suspend, pcmcsa_suspend),
 1027         DEVMETHOD(device_resume, pcmcsa_resume),
 1028 
 1029         { 0, 0 },
 1030 };
 1031 
 1032 static driver_t pcmcsa_driver = {
 1033         "pcm",
 1034         pcmcsa_methods,
 1035         PCM_SOFTC_SIZE,
 1036 };
 1037 
 1038 DRIVER_MODULE(snd_csapcm, csa, pcmcsa_driver, 0, 0);
 1039 MODULE_DEPEND(snd_csapcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
 1040 MODULE_DEPEND(snd_csapcm, snd_csa, 1, 1, 1);
 1041 MODULE_VERSION(snd_csapcm, 1);

Cache object: 205d33ab9a267f23743279fb53c04c13


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