csapcm.c revision 55320
155320Stanimura/* 253553Stanimura * Copyright (c) 1999 Seigo Tanimura 353553Stanimura * All rights reserved. 453553Stanimura * 554377Stanimura * Portions of this source are based on cwcealdr.cpp and dhwiface.cpp in 654377Stanimura * cwcealdr1.zip, the sample sources by Crystal Semiconductor. 754377Stanimura * Copyright (c) 1996-1998 Crystal Semiconductor Corp. 854377Stanimura * 953553Stanimura * Redistribution and use in source and binary forms, with or without 1053553Stanimura * modification, are permitted provided that the following conditions 1153553Stanimura * are met: 1253553Stanimura * 1. Redistributions of source code must retain the above copyright 1353553Stanimura * notice, this list of conditions and the following disclaimer. 1453553Stanimura * 2. Redistributions in binary form must reproduce the above copyright 1553553Stanimura * notice, this list of conditions and the following disclaimer in the 1653553Stanimura * documentation and/or other materials provided with the distribution. 1753553Stanimura * 1853553Stanimura * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1953553Stanimura * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2053553Stanimura * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2153553Stanimura * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2253553Stanimura * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2353553Stanimura * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2453553Stanimura * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2553553Stanimura * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2653553Stanimura * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2753553Stanimura * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2853553Stanimura * SUCH DAMAGE. 2953553Stanimura * 3053553Stanimura * $FreeBSD: head/sys/dev/sound/pci/csapcm.c 55320 2000-01-03 02:51:16Z tanimura $ 3153553Stanimura */ 3253553Stanimura 3353553Stanimura#include <sys/soundcard.h> 3453553Stanimura#include <dev/sound/pcm/sound.h> 3553553Stanimura#include <dev/sound/pcm/ac97.h> 3653553Stanimura#include <dev/sound/chip.h> 3753553Stanimura#include <dev/sound/pci/csareg.h> 3853553Stanimura#include <dev/sound/pci/csavar.h> 3953553Stanimura 4053553Stanimura#include <pci/pcireg.h> 4153553Stanimura#include <pci/pcivar.h> 4253553Stanimura 4353553Stanimura/* device private data */ 4453553Stanimurastruct csa_info; 4553553Stanimura 4653553Stanimurastruct csa_chinfo { 4753553Stanimura struct csa_info *parent; 4853553Stanimura pcm_channel *channel; 4953553Stanimura snd_dbuf *buffer; 5053553Stanimura int dir; 5153553Stanimura u_int32_t fmt; 5253553Stanimura}; 5353553Stanimura 5453553Stanimurastruct csa_info { 5553553Stanimura csa_res res; /* resource */ 5653553Stanimura void *ih; /* Interrupt cookie */ 5753553Stanimura bus_dma_tag_t parent_dmat; /* DMA tag */ 5855320Stanimura struct csa_bridgeinfo *binfo; /* The state of the parent. */ 5953553Stanimura 6053553Stanimura /* Contents of board's registers */ 6153553Stanimura u_long pfie; 6253553Stanimura u_long pctl; 6353553Stanimura u_long cctl; 6453553Stanimura struct csa_chinfo pch, rch; 6553553Stanimura}; 6653553Stanimura 6753553Stanimura/* -------------------------------------------------------------------- */ 6853553Stanimura 6953553Stanimura/* prototypes */ 7053553Stanimurastatic int csa_init(struct csa_info *); 7153553Stanimurastatic void csa_intr(void *); 7253553Stanimurastatic void csa_setplaysamplerate(csa_res *resp, u_long ulInRate); 7353553Stanimurastatic void csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate); 7453553Stanimurastatic void csa_startplaydma(struct csa_info *csa); 7553553Stanimurastatic void csa_startcapturedma(struct csa_info *csa); 7653553Stanimurastatic void csa_stopplaydma(struct csa_info *csa); 7753553Stanimurastatic void csa_stopcapturedma(struct csa_info *csa); 7853553Stanimurastatic void csa_powerupadc(csa_res *resp); 7953553Stanimurastatic void csa_powerupdac(csa_res *resp); 8053553Stanimurastatic int csa_startdsp(csa_res *resp); 8153553Stanimurastatic int csa_allocres(struct csa_info *scp, device_t dev); 8253553Stanimurastatic void csa_releaseres(struct csa_info *scp, device_t dev); 8353553Stanimura 8453553Stanimura/* talk to the codec - called from ac97.c */ 8553553Stanimurastatic u_int32_t csa_rdcd(void *, int); 8653553Stanimurastatic void csa_wrcd(void *, int, u_int32_t); 8753553Stanimura 8853553Stanimura/* channel interface */ 8953553Stanimurastatic void *csachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 9053553Stanimurastatic int csachan_setdir(void *data, int dir); 9153553Stanimurastatic int csachan_setformat(void *data, u_int32_t format); 9253553Stanimurastatic int csachan_setspeed(void *data, u_int32_t speed); 9353553Stanimurastatic int csachan_setblocksize(void *data, u_int32_t blocksize); 9453553Stanimurastatic int csachan_trigger(void *data, int go); 9553553Stanimurastatic int csachan_getptr(void *data); 9653553Stanimurastatic pcmchan_caps *csachan_getcaps(void *data); 9753553Stanimura 9853553Stanimurastatic pcmchan_caps csa_playcaps = { 9953553Stanimura 8000, 48000, 10053553Stanimura AFMT_STEREO | AFMT_U8 | AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, 10153553Stanimura AFMT_STEREO | AFMT_S16_LE 10253553Stanimura}; 10353553Stanimura 10453553Stanimurastatic pcmchan_caps csa_reccaps = { 10553553Stanimura 11025, 48000, 10653553Stanimura AFMT_STEREO | AFMT_S16_LE, 10753553Stanimura AFMT_STEREO | AFMT_S16_LE 10853553Stanimura}; 10953553Stanimura 11053553Stanimurastatic pcm_channel csa_chantemplate = { 11153553Stanimura csachan_init, 11253553Stanimura csachan_setdir, 11353553Stanimura csachan_setformat, 11453553Stanimura csachan_setspeed, 11553553Stanimura csachan_setblocksize, 11653553Stanimura csachan_trigger, 11753553Stanimura csachan_getptr, 11853553Stanimura csachan_getcaps, 11953553Stanimura}; 12053553Stanimura 12153553Stanimura/* -------------------------------------------------------------------- */ 12253553Stanimura 12353553Stanimura/* channel interface */ 12453553Stanimurastatic void * 12553553Stanimuracsachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 12653553Stanimura{ 12753553Stanimura struct csa_info *csa = devinfo; 12853553Stanimura struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch; 12953553Stanimura 13053553Stanimura ch->parent = csa; 13153553Stanimura ch->channel = c; 13253553Stanimura ch->buffer = b; 13353553Stanimura ch->buffer->bufsize = CS461x_BUFFSIZE; 13453553Stanimura if (chn_allocbuf(ch->buffer, csa->parent_dmat) == -1) return NULL; 13553553Stanimura return ch; 13653553Stanimura} 13753553Stanimura 13853553Stanimurastatic int 13953553Stanimuracsachan_setdir(void *data, int dir) 14053553Stanimura{ 14153553Stanimura struct csa_chinfo *ch = data; 14253553Stanimura struct csa_info *csa = ch->parent; 14353553Stanimura csa_res *resp; 14453553Stanimura 14553553Stanimura resp = &csa->res; 14653553Stanimura 14753553Stanimura if (dir == PCMDIR_PLAY) 14853553Stanimura csa_writemem(resp, BA1_PBA, vtophys(ch->buffer->buf)); 14953553Stanimura else 15053553Stanimura csa_writemem(resp, BA1_CBA, vtophys(ch->buffer->buf)); 15153553Stanimura ch->dir = dir; 15253553Stanimura return 0; 15353553Stanimura} 15453553Stanimura 15553553Stanimurastatic int 15653553Stanimuracsachan_setformat(void *data, u_int32_t format) 15753553Stanimura{ 15853553Stanimura struct csa_chinfo *ch = data; 15953553Stanimura struct csa_info *csa = ch->parent; 16053553Stanimura u_long pdtc; 16153553Stanimura csa_res *resp; 16253553Stanimura 16353553Stanimura resp = &csa->res; 16453553Stanimura 16553553Stanimura if (ch->dir == PCMDIR_REC) 16653553Stanimura csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 16753553Stanimura else { 16853553Stanimura csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; 16953553Stanimura if (format & AFMT_U8 || format & AFMT_U16_LE || format & AFMT_U16_BE) 17053553Stanimura csa->pfie |= 0x8000; 17153553Stanimura if (format & AFMT_S16_BE || format & AFMT_U16_BE) 17253553Stanimura csa->pfie |= 0x4000; 17353553Stanimura if (!(format & AFMT_STEREO)) 17453553Stanimura csa->pfie |= 0x2000; 17553553Stanimura if (format & AFMT_U8 || format & AFMT_S8) 17653553Stanimura csa->pfie |= 0x1000; 17753553Stanimura csa_writemem(resp, BA1_PFIE, csa->pfie); 17853553Stanimura pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000003ff; 17953553Stanimura if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) && (format & AFMT_STEREO)) 18053553Stanimura pdtc |= 0x00f; 18153553Stanimura else if ((format & AFMT_S16_BE || format & AFMT_U16_BE || format & AFMT_S16_LE || format & AFMT_U16_LE) || (format & AFMT_STEREO)) 18253553Stanimura pdtc |= 0x007; 18353553Stanimura else 18453553Stanimura pdtc |= 0x003; 18553553Stanimura csa_writemem(resp, BA1_PDTC, pdtc); 18653553Stanimura } 18753553Stanimura ch->fmt = format; 18853553Stanimura return 0; 18953553Stanimura} 19053553Stanimura 19153553Stanimurastatic int 19253553Stanimuracsachan_setspeed(void *data, u_int32_t speed) 19353553Stanimura{ 19453553Stanimura struct csa_chinfo *ch = data; 19553553Stanimura struct csa_info *csa = ch->parent; 19653553Stanimura csa_res *resp; 19753553Stanimura 19853553Stanimura resp = &csa->res; 19953553Stanimura 20053553Stanimura if (ch->dir == PCMDIR_PLAY) 20153553Stanimura csa_setplaysamplerate(resp, speed); 20253553Stanimura else if (ch->dir == PCMDIR_REC) 20353553Stanimura csa_setcapturesamplerate(resp, speed); 20453553Stanimura 20553553Stanimura /* rec/play speeds locked together - should indicate in flags */ 20653553Stanimura#if 0 20753553Stanimura if (ch->direction == PCMDIR_PLAY) d->rec[0].speed = speed; 20853553Stanimura else d->play[0].speed = speed; 20953553Stanimura#endif 21053553Stanimura return speed; /* XXX calc real speed */ 21153553Stanimura} 21253553Stanimura 21353553Stanimurastatic void 21453553Stanimuracsa_setplaysamplerate(csa_res *resp, u_long ulInRate) 21553553Stanimura{ 21653553Stanimura u_long ulTemp1, ulTemp2; 21753553Stanimura u_long ulPhiIncr; 21853553Stanimura u_long ulCorrectionPerGOF, ulCorrectionPerSec; 21953553Stanimura u_long ulOutRate; 22053553Stanimura 22153553Stanimura ulOutRate = 48000; 22253553Stanimura 22353553Stanimura /* 22453553Stanimura * Compute the values used to drive the actual sample rate conversion. 22553553Stanimura * The following formulas are being computed, using inline assembly 22653553Stanimura * since we need to use 64 bit arithmetic to compute the values: 22753553Stanimura * 22853553Stanimura * ulPhiIncr = floor((Fs,in * 2^26) / Fs,out) 22953553Stanimura * ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) / 23053553Stanimura * GOF_PER_SEC) 23153553Stanimura * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - 23253553Stanimura * GOF_PER_SEC * ulCorrectionPerGOF 23353553Stanimura * 23453553Stanimura * i.e. 23553553Stanimura * 23653553Stanimura * ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) 23753553Stanimura * ulCorrectionPerGOF:ulCorrectionPerSec = 23853553Stanimura * dividend:remainder(ulOther / GOF_PER_SEC) 23953553Stanimura */ 24053553Stanimura ulTemp1 = ulInRate << 16; 24153553Stanimura ulPhiIncr = ulTemp1 / ulOutRate; 24253553Stanimura ulTemp1 -= ulPhiIncr * ulOutRate; 24353553Stanimura ulTemp1 <<= 10; 24453553Stanimura ulPhiIncr <<= 10; 24553553Stanimura ulTemp2 = ulTemp1 / ulOutRate; 24653553Stanimura ulPhiIncr += ulTemp2; 24753553Stanimura ulTemp1 -= ulTemp2 * ulOutRate; 24853553Stanimura ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC; 24953553Stanimura ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC; 25053553Stanimura ulCorrectionPerSec = ulTemp1; 25153553Stanimura 25253553Stanimura /* 25353553Stanimura * Fill in the SampleRateConverter control block. 25453553Stanimura */ 25553553Stanimura csa_writemem(resp, BA1_PSRC, ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF)); 25653553Stanimura csa_writemem(resp, BA1_PPI, ulPhiIncr); 25753553Stanimura} 25853553Stanimura 25953553Stanimurastatic void 26053553Stanimuracsa_setcapturesamplerate(csa_res *resp, u_long ulOutRate) 26153553Stanimura{ 26253553Stanimura u_long ulPhiIncr, ulCoeffIncr, ulTemp1, ulTemp2; 26353553Stanimura u_long ulCorrectionPerGOF, ulCorrectionPerSec, ulInitialDelay; 26453553Stanimura u_long dwFrameGroupLength, dwCnt; 26553553Stanimura u_long ulInRate; 26653553Stanimura 26753553Stanimura ulInRate = 48000; 26853553Stanimura 26953553Stanimura /* 27053553Stanimura * We can only decimate by up to a factor of 1/9th the hardware rate. 27153553Stanimura * Return an error if an attempt is made to stray outside that limit. 27253553Stanimura */ 27353553Stanimura if((ulOutRate * 9) < ulInRate) 27453553Stanimura return; 27553553Stanimura 27653553Stanimura /* 27753553Stanimura * We can not capture at at rate greater than the Input Rate (48000). 27853553Stanimura * Return an error if an attempt is made to stray outside that limit. 27953553Stanimura */ 28053553Stanimura if(ulOutRate > ulInRate) 28153553Stanimura return; 28253553Stanimura 28353553Stanimura /* 28453553Stanimura * Compute the values used to drive the actual sample rate conversion. 28553553Stanimura * The following formulas are being computed, using inline assembly 28653553Stanimura * since we need to use 64 bit arithmetic to compute the values: 28753553Stanimura * 28853553Stanimura * ulCoeffIncr = -floor((Fs,out * 2^23) / Fs,in) 28953553Stanimura * ulPhiIncr = floor((Fs,in * 2^26) / Fs,out) 29053553Stanimura * ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) / 29153553Stanimura * GOF_PER_SEC) 29253553Stanimura * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - 29353553Stanimura * GOF_PER_SEC * ulCorrectionPerGOF 29453553Stanimura * ulInitialDelay = ceil((24 * Fs,in) / Fs,out) 29553553Stanimura * 29653553Stanimura * i.e. 29753553Stanimura * 29853553Stanimura * ulCoeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) 29953553Stanimura * ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) 30053553Stanimura * ulCorrectionPerGOF:ulCorrectionPerSec = 30153553Stanimura * dividend:remainder(ulOther / GOF_PER_SEC) 30253553Stanimura * ulInitialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) 30353553Stanimura */ 30453553Stanimura ulTemp1 = ulOutRate << 16; 30553553Stanimura ulCoeffIncr = ulTemp1 / ulInRate; 30653553Stanimura ulTemp1 -= ulCoeffIncr * ulInRate; 30753553Stanimura ulTemp1 <<= 7; 30853553Stanimura ulCoeffIncr <<= 7; 30953553Stanimura ulCoeffIncr += ulTemp1 / ulInRate; 31053553Stanimura ulCoeffIncr ^= 0xFFFFFFFF; 31153553Stanimura ulCoeffIncr++; 31253553Stanimura ulTemp1 = ulInRate << 16; 31353553Stanimura ulPhiIncr = ulTemp1 / ulOutRate; 31453553Stanimura ulTemp1 -= ulPhiIncr * ulOutRate; 31553553Stanimura ulTemp1 <<= 10; 31653553Stanimura ulPhiIncr <<= 10; 31753553Stanimura ulTemp2 = ulTemp1 / ulOutRate; 31853553Stanimura ulPhiIncr += ulTemp2; 31953553Stanimura ulTemp1 -= ulTemp2 * ulOutRate; 32053553Stanimura ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC; 32153553Stanimura ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC; 32253553Stanimura ulCorrectionPerSec = ulTemp1; 32353553Stanimura ulInitialDelay = ((ulInRate * 24) + ulOutRate - 1) / ulOutRate; 32453553Stanimura 32553553Stanimura /* 32653553Stanimura * Fill in the VariDecimate control block. 32753553Stanimura */ 32853553Stanimura csa_writemem(resp, BA1_CSRC, 32953553Stanimura ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF)); 33053553Stanimura csa_writemem(resp, BA1_CCI, ulCoeffIncr); 33153553Stanimura csa_writemem(resp, BA1_CD, 33253553Stanimura (((BA1_VARIDEC_BUF_1 + (ulInitialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); 33353553Stanimura csa_writemem(resp, BA1_CPI, ulPhiIncr); 33453553Stanimura 33553553Stanimura /* 33653553Stanimura * Figure out the frame group length for the write back task. Basically, 33753553Stanimura * this is just the factors of 24000 (2^6*3*5^3) that are not present in 33853553Stanimura * the output sample rate. 33953553Stanimura */ 34053553Stanimura dwFrameGroupLength = 1; 34153553Stanimura for(dwCnt = 2; dwCnt <= 64; dwCnt *= 2) 34253553Stanimura { 34353553Stanimura if(((ulOutRate / dwCnt) * dwCnt) != 34453553Stanimura ulOutRate) 34553553Stanimura { 34653553Stanimura dwFrameGroupLength *= 2; 34753553Stanimura } 34853553Stanimura } 34953553Stanimura if(((ulOutRate / 3) * 3) != 35053553Stanimura ulOutRate) 35153553Stanimura { 35253553Stanimura dwFrameGroupLength *= 3; 35353553Stanimura } 35453553Stanimura for(dwCnt = 5; dwCnt <= 125; dwCnt *= 5) 35553553Stanimura { 35653553Stanimura if(((ulOutRate / dwCnt) * dwCnt) != 35753553Stanimura ulOutRate) 35853553Stanimura { 35953553Stanimura dwFrameGroupLength *= 5; 36053553Stanimura } 36153553Stanimura } 36253553Stanimura 36353553Stanimura /* 36453553Stanimura * Fill in the WriteBack control block. 36553553Stanimura */ 36653553Stanimura csa_writemem(resp, BA1_CFG1, dwFrameGroupLength); 36753553Stanimura csa_writemem(resp, BA1_CFG2, (0x00800000 | dwFrameGroupLength)); 36853553Stanimura csa_writemem(resp, BA1_CCST, 0x0000FFFF); 36953553Stanimura csa_writemem(resp, BA1_CSPB, ((65536 * ulOutRate) / 24000)); 37053553Stanimura csa_writemem(resp, (BA1_CSPB + 4), 0x0000FFFF); 37153553Stanimura} 37253553Stanimura 37353553Stanimurastatic int 37453553Stanimuracsachan_setblocksize(void *data, u_int32_t blocksize) 37553553Stanimura{ 37653553Stanimura#if notdef 37753553Stanimura return blocksize; 37853553Stanimura#else 37953553Stanimura struct csa_chinfo *ch = data; 38053553Stanimura return ch->buffer->bufsize / 2; 38153553Stanimura#endif /* notdef */ 38253553Stanimura} 38353553Stanimura 38453553Stanimurastatic int 38553553Stanimuracsachan_trigger(void *data, int go) 38653553Stanimura{ 38753553Stanimura struct csa_chinfo *ch = data; 38853553Stanimura struct csa_info *csa = ch->parent; 38953553Stanimura 39055204Scg if (go == PCMTRIG_EMLDMAWR) return 0; 39153553Stanimura if (ch->dir == PCMDIR_PLAY) { 39253553Stanimura if (go == PCMTRIG_START) 39353553Stanimura csa_startplaydma(csa); 39453553Stanimura else 39553553Stanimura csa_stopplaydma(csa); 39653553Stanimura } else { 39753553Stanimura if (go == PCMTRIG_START) 39853553Stanimura csa_startcapturedma(csa); 39953553Stanimura else 40053553Stanimura csa_stopcapturedma(csa); 40153553Stanimura } 40253553Stanimura return 0; 40353553Stanimura} 40453553Stanimura 40553553Stanimurastatic void 40653553Stanimuracsa_startplaydma(struct csa_info *csa) 40753553Stanimura{ 40853553Stanimura csa_res *resp; 40953553Stanimura u_long ul; 41053553Stanimura 41153553Stanimura resp = &csa->res; 41253553Stanimura ul = csa_readmem(resp, BA1_PCTL); 41353553Stanimura ul &= 0x0000ffff; 41453553Stanimura csa_writemem(resp, BA1_PCTL, ul | csa->pctl); 41553553Stanimura csa_writemem(resp, BA1_PVOL, 0x80008000); 41653553Stanimura} 41753553Stanimura 41853553Stanimurastatic void 41953553Stanimuracsa_startcapturedma(struct csa_info *csa) 42053553Stanimura{ 42153553Stanimura csa_res *resp; 42253553Stanimura u_long ul; 42353553Stanimura 42453553Stanimura resp = &csa->res; 42553553Stanimura ul = csa_readmem(resp, BA1_CCTL); 42653553Stanimura ul &= 0xffff0000; 42753553Stanimura csa_writemem(resp, BA1_CCTL, ul | csa->cctl); 42853553Stanimura csa_writemem(resp, BA1_CVOL, 0x80008000); 42953553Stanimura} 43053553Stanimura 43153553Stanimurastatic void 43253553Stanimuracsa_stopplaydma(struct csa_info *csa) 43353553Stanimura{ 43453553Stanimura csa_res *resp; 43553553Stanimura u_long ul; 43653553Stanimura 43753553Stanimura resp = &csa->res; 43853553Stanimura ul = csa_readmem(resp, BA1_PCTL); 43953553Stanimura csa->pctl = ul & 0xffff0000; 44053553Stanimura csa_writemem(resp, BA1_PCTL, ul & 0x0000ffff); 44153553Stanimura csa_writemem(resp, BA1_PVOL, 0xffffffff); 44255320Stanimura 44355320Stanimura /* Clear the serial fifos. */ 44455320Stanimura csa_clearserialfifos(resp); 44553553Stanimura} 44653553Stanimura 44753553Stanimurastatic void 44853553Stanimuracsa_stopcapturedma(struct csa_info *csa) 44953553Stanimura{ 45053553Stanimura csa_res *resp; 45153553Stanimura u_long ul; 45253553Stanimura 45353553Stanimura resp = &csa->res; 45453553Stanimura ul = csa_readmem(resp, BA1_CCTL); 45553553Stanimura csa->cctl = ul & 0x0000ffff; 45653553Stanimura csa_writemem(resp, BA1_CCTL, ul & 0xffff0000); 45753553Stanimura csa_writemem(resp, BA1_CVOL, 0xffffffff); 45853553Stanimura} 45953553Stanimura 46053553Stanimurastatic void 46153553Stanimuracsa_powerupdac(csa_res *resp) 46253553Stanimura{ 46353553Stanimura int i; 46453553Stanimura u_long ul; 46553553Stanimura 46653553Stanimura /* 46753553Stanimura * Power on the DACs on the AC97 codec. We turn off the DAC 46853553Stanimura * powerdown bit and write the new value of the power control 46953553Stanimura * register. 47053553Stanimura */ 47153553Stanimura ul = csa_readio(resp, BA0_AC97_POWERDOWN); 47253553Stanimura ul &= 0xfdff; 47353553Stanimura csa_writeio(resp, BA0_AC97_POWERDOWN, ul); 47453553Stanimura 47553553Stanimura /* 47653553Stanimura * Now, we wait until we sample a DAC ready state. 47753553Stanimura */ 47853553Stanimura for (i = 0 ; i < 32 ; i++) { 47953553Stanimura /* 48053553Stanimura * First, lets wait a short while to let things settle out a 48153553Stanimura * bit, and to prevent retrying the read too quickly. 48253553Stanimura */ 48353553Stanimura DELAY(125); 48453553Stanimura 48553553Stanimura /* 48653553Stanimura * Read the current state of the power control register. 48753553Stanimura */ 48853553Stanimura ul = csa_readio(resp, BA0_AC97_POWERDOWN); 48953553Stanimura 49053553Stanimura /* 49153553Stanimura * If the DAC ready state bit is set, then stop waiting. 49253553Stanimura */ 49353553Stanimura if ((ul & 0x2) != 0) 49453553Stanimura break; 49553553Stanimura } 49653553Stanimura /* 49753553Stanimura * The DACs are now calibrated, so we can unmute the DAC output. 49853553Stanimura */ 49953553Stanimura csa_writeio(resp, BA0_AC97_PCM_OUT_VOLUME, 0x0808); 50053553Stanimura} 50153553Stanimura 50253553Stanimurastatic void 50353553Stanimuracsa_powerupadc(csa_res *resp) 50453553Stanimura{ 50553553Stanimura int i; 50653553Stanimura u_long ul; 50753553Stanimura 50853553Stanimura /* 50953553Stanimura * Power on the ADCs on the AC97 codec. We turn off the ADC 51053553Stanimura * powerdown bit and write the new value of the power control 51153553Stanimura * register. 51253553Stanimura */ 51353553Stanimura ul = csa_readio(resp, BA0_AC97_POWERDOWN); 51453553Stanimura ul &= 0xfeff; 51553553Stanimura csa_writeio(resp, BA0_AC97_POWERDOWN, ul); 51653553Stanimura 51753553Stanimura /* 51853553Stanimura * Now, we wait until we sample a ADC ready state. 51953553Stanimura */ 52053553Stanimura for (i = 0 ; i < 32 ; i++) { 52153553Stanimura /* 52253553Stanimura * First, lets wait a short while to let things settle out a 52353553Stanimura * bit, and to prevent retrying the read too quickly. 52453553Stanimura */ 52553553Stanimura DELAY(125); 52653553Stanimura 52753553Stanimura /* 52853553Stanimura * Read the current state of the power control register. 52953553Stanimura */ 53053553Stanimura ul = csa_readio(resp, BA0_AC97_POWERDOWN); 53153553Stanimura 53253553Stanimura /* 53353553Stanimura * If the ADC ready state bit is set, then stop waiting. 53453553Stanimura */ 53553553Stanimura if ((ul & 0x1) != 0) 53653553Stanimura break; 53753553Stanimura } 53853553Stanimura} 53953553Stanimura 54053553Stanimurastatic int 54153553Stanimuracsa_startdsp(csa_res *resp) 54253553Stanimura{ 54353553Stanimura int i; 54453553Stanimura u_long ul; 54553553Stanimura 54653553Stanimura /* 54753553Stanimura * Set the frame timer to reflect the number of cycles per frame. 54853553Stanimura */ 54953553Stanimura csa_writemem(resp, BA1_FRMT, 0xadf); 55053553Stanimura 55153553Stanimura /* 55253553Stanimura * Turn on the run, run at frame, and DMA enable bits in the local copy of 55353553Stanimura * the SP control register. 55453553Stanimura */ 55553553Stanimura csa_writemem(resp, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN); 55653553Stanimura 55753553Stanimura /* 55853553Stanimura * Wait until the run at frame bit resets itself in the SP control 55953553Stanimura * register. 56053553Stanimura */ 56153553Stanimura ul = 0; 56253553Stanimura for (i = 0 ; i < 25 ; i++) { 56353553Stanimura /* 56453553Stanimura * Wait a little bit, so we don't issue PCI reads too frequently. 56553553Stanimura */ 56653553Stanimura#if notdef 56753553Stanimura DELAY(1000); 56853553Stanimura#else 56953553Stanimura DELAY(125); 57053553Stanimura#endif /* notdef */ 57153553Stanimura /* 57253553Stanimura * Fetch the current value of the SP status register. 57353553Stanimura */ 57453553Stanimura ul = csa_readmem(resp, BA1_SPCR); 57553553Stanimura 57653553Stanimura /* 57753553Stanimura * If the run at frame bit has reset, then stop waiting. 57853553Stanimura */ 57953553Stanimura if((ul & SPCR_RUNFR) == 0) 58053553Stanimura break; 58153553Stanimura } 58253553Stanimura /* 58353553Stanimura * If the run at frame bit never reset, then return an error. 58453553Stanimura */ 58553553Stanimura if((ul & SPCR_RUNFR) != 0) 58653553Stanimura return (EAGAIN); 58753553Stanimura 58853553Stanimura return (0); 58953553Stanimura} 59053553Stanimura 59153553Stanimurastatic int 59253553Stanimuracsachan_getptr(void *data) 59353553Stanimura{ 59453553Stanimura struct csa_chinfo *ch = data; 59553553Stanimura struct csa_info *csa = ch->parent; 59653553Stanimura csa_res *resp; 59753553Stanimura int ptr; 59853553Stanimura 59953553Stanimura resp = &csa->res; 60053553Stanimura 60153553Stanimura if (ch->dir == PCMDIR_PLAY) { 60253553Stanimura ptr = csa_readmem(resp, BA1_PBA) - vtophys(ch->buffer->buf); 60353553Stanimura if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0) 60453553Stanimura ptr >>= 1; 60553553Stanimura } else { 60653553Stanimura ptr = csa_readmem(resp, BA1_CBA) - vtophys(ch->buffer->buf); 60753553Stanimura if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0) 60853553Stanimura ptr >>= 1; 60953553Stanimura } 61053553Stanimura 61153553Stanimura return (ptr); 61253553Stanimura} 61353553Stanimura 61453553Stanimurastatic pcmchan_caps * 61553553Stanimuracsachan_getcaps(void *data) 61653553Stanimura{ 61753553Stanimura struct csa_chinfo *ch = data; 61853553Stanimura return (ch->dir == PCMDIR_PLAY)? &csa_playcaps : &csa_reccaps; 61953553Stanimura} 62053553Stanimura 62153553Stanimura/* The interrupt handler */ 62253553Stanimurastatic void 62353553Stanimuracsa_intr (void *p) 62453553Stanimura{ 62553553Stanimura struct csa_info *csa = p; 62653553Stanimura 62755320Stanimura if ((csa->binfo->hisr & HISR_VC0) != 0) 62853553Stanimura chn_intr(csa->pch.channel); 62955320Stanimura if ((csa->binfo->hisr & HISR_VC1) != 0) 63053553Stanimura chn_intr(csa->rch.channel); 63153553Stanimura} 63253553Stanimura 63353553Stanimura/* -------------------------------------------------------------------- */ 63453553Stanimura 63553553Stanimura/* 63653553Stanimura * Probe and attach the card 63753553Stanimura */ 63853553Stanimura 63953553Stanimurastatic int 64053553Stanimuracsa_init(struct csa_info *csa) 64153553Stanimura{ 64253553Stanimura csa_res *resp; 64353553Stanimura 64453553Stanimura resp = &csa->res; 64553553Stanimura 64653553Stanimura csa->pfie = 0; 64753553Stanimura csa_stopplaydma(csa); 64853553Stanimura csa_stopcapturedma(csa); 64953553Stanimura 65053553Stanimura /* Crank up the power on the DAC and ADC. */ 65153553Stanimura csa_powerupadc(resp); 65253553Stanimura csa_powerupdac(resp); 65353553Stanimura 65453553Stanimura csa_setplaysamplerate(resp, 8000); 65553553Stanimura csa_setcapturesamplerate(resp, 8000); 65653553Stanimura 65753553Stanimura if (csa_startdsp(resp)) 65853553Stanimura return (1); 65953553Stanimura 66053553Stanimura return 0; 66153553Stanimura} 66253553Stanimura 66353553Stanimura/* Allocates resources. */ 66453553Stanimurastatic int 66553553Stanimuracsa_allocres(struct csa_info *csa, device_t dev) 66653553Stanimura{ 66753553Stanimura csa_res *resp; 66853553Stanimura 66953553Stanimura resp = &csa->res; 67053553Stanimura if (resp->io == NULL) { 67153553Stanimura resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, CS461x_IO_SIZE, RF_ACTIVE); 67253553Stanimura if (resp->io == NULL) 67353553Stanimura return (1); 67453553Stanimura } 67553553Stanimura if (resp->mem == NULL) { 67653553Stanimura resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, CS461x_MEM_SIZE, RF_ACTIVE); 67753553Stanimura if (resp->mem == NULL) 67853553Stanimura return (1); 67953553Stanimura } 68053553Stanimura if (resp->irq == NULL) { 68153553Stanimura resp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &resp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 68253553Stanimura if (resp->irq == NULL) 68353553Stanimura return (1); 68453553Stanimura } 68553553Stanimura if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/CS461x_BUFFSIZE, /*boundary*/CS461x_BUFFSIZE, 68653553Stanimura /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 68753553Stanimura /*highaddr*/BUS_SPACE_MAXADDR, 68853553Stanimura /*filter*/NULL, /*filterarg*/NULL, 68953553Stanimura /*maxsize*/CS461x_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 69053553Stanimura /*flags*/0, &csa->parent_dmat) != 0) 69153553Stanimura return (1); 69253553Stanimura 69353553Stanimura return (0); 69453553Stanimura} 69553553Stanimura 69653553Stanimura/* Releases resources. */ 69753553Stanimurastatic void 69853553Stanimuracsa_releaseres(struct csa_info *csa, device_t dev) 69953553Stanimura{ 70053553Stanimura csa_res *resp; 70153553Stanimura 70253553Stanimura resp = &csa->res; 70353553Stanimura if (resp->irq != NULL) { 70453553Stanimura bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq); 70553553Stanimura resp->irq = NULL; 70653553Stanimura } 70753553Stanimura if (resp->io != NULL) { 70853553Stanimura bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io); 70953553Stanimura resp->io = NULL; 71053553Stanimura } 71153553Stanimura if (resp->mem != NULL) { 71253553Stanimura bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem); 71353553Stanimura resp->mem = NULL; 71453553Stanimura } 71553553Stanimura} 71653553Stanimura 71753553Stanimurastatic int pcmcsa_probe(device_t dev); 71853553Stanimurastatic int pcmcsa_attach(device_t dev); 71953553Stanimura 72053553Stanimurastatic int 72153553Stanimurapcmcsa_probe(device_t dev) 72253553Stanimura{ 72353553Stanimura char *s; 72453553Stanimura struct sndcard_func *func; 72553553Stanimura 72653553Stanimura /* The parent device has already been probed. */ 72753553Stanimura 72853553Stanimura func = device_get_ivars(dev); 72953553Stanimura if (func == NULL || func->func != SCF_PCM) 73053553Stanimura return (ENXIO); 73153553Stanimura 73253553Stanimura s = "CS461x PCM Audio"; 73353553Stanimura 73453553Stanimura device_set_desc(dev, s); 73553553Stanimura return (0); 73653553Stanimura} 73753553Stanimura 73853553Stanimurastatic int 73953553Stanimurapcmcsa_attach(device_t dev) 74053553Stanimura{ 74153553Stanimura snddev_info *devinfo; 74253553Stanimura struct csa_info *csa; 74353553Stanimura csa_res *resp; 74453553Stanimura int unit; 74553553Stanimura char status[SND_STATUSLEN]; 74653553Stanimura struct ac97_info *codec; 74755320Stanimura struct sndcard_func *func; 74853553Stanimura 74953553Stanimura devinfo = device_get_softc(dev); 75053553Stanimura csa = malloc(sizeof(*csa), M_DEVBUF, M_NOWAIT); 75153553Stanimura if (csa == NULL) 75253553Stanimura return (ENOMEM); 75353553Stanimura bzero(csa, sizeof(*csa)); 75453553Stanimura unit = device_get_unit(dev); 75555320Stanimura func = device_get_ivars(dev); 75655320Stanimura csa->binfo = func->varinfo; 75753553Stanimura 75853553Stanimura /* Allocate the resources. */ 75953553Stanimura resp = &csa->res; 76053553Stanimura resp->io_rid = CS461x_IO_OFFSET; 76153553Stanimura resp->mem_rid = CS461x_MEM_OFFSET; 76253553Stanimura resp->irq_rid = 0; 76353553Stanimura if (csa_allocres(csa, dev)) { 76453553Stanimura csa_releaseres(csa, dev); 76553553Stanimura return (ENXIO); 76653553Stanimura } 76753553Stanimura 76853553Stanimura if (csa_init(csa)) { 76953553Stanimura csa_releaseres(csa, dev); 77053553Stanimura return (ENXIO); 77153553Stanimura } 77253553Stanimura codec = ac97_create(csa, csa_rdcd, csa_wrcd); 77353553Stanimura if (codec == NULL) 77453553Stanimura return (ENXIO); 77553553Stanimura mixer_init(devinfo, &ac97_mixer, codec); 77653553Stanimura 77753553Stanimura snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq)); 77853553Stanimura 77953553Stanimura /* Enable interrupt. */ 78053553Stanimura if (bus_setup_intr(dev, resp->irq, INTR_TYPE_TTY, csa_intr, csa, &csa->ih)) { 78153553Stanimura csa_releaseres(csa, dev); 78253553Stanimura return (ENXIO); 78353553Stanimura } 78453553Stanimura csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f); 78553553Stanimura csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 78653553Stanimura 78753553Stanimura if (pcm_register(dev, csa, 1, 1)) { 78853553Stanimura csa_releaseres(csa, dev); 78953553Stanimura return (ENXIO); 79053553Stanimura } 79153553Stanimura pcm_addchan(dev, PCMDIR_REC, &csa_chantemplate, csa); 79253553Stanimura pcm_addchan(dev, PCMDIR_PLAY, &csa_chantemplate, csa); 79353553Stanimura pcm_setstatus(dev, status); 79453553Stanimura 79553553Stanimura return (0); 79653553Stanimura} 79753553Stanimura 79853553Stanimura/* ac97 codec */ 79953553Stanimura 80053553Stanimurastatic u_int32_t 80153553Stanimuracsa_rdcd(void *devinfo, int regno) 80253553Stanimura{ 80353553Stanimura u_int32_t data; 80453553Stanimura struct csa_info *csa = (struct csa_info *)devinfo; 80553553Stanimura 80653553Stanimura if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data)) 80753553Stanimura data = 0; 80853553Stanimura 80953553Stanimura return data; 81053553Stanimura} 81153553Stanimura 81253553Stanimurastatic void 81353553Stanimuracsa_wrcd(void *devinfo, int regno, u_int32_t data) 81453553Stanimura{ 81553553Stanimura struct csa_info *csa = (struct csa_info *)devinfo; 81653553Stanimura 81753553Stanimura csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data); 81853553Stanimura} 81953553Stanimura 82053553Stanimurastatic device_method_t pcmcsa_methods[] = { 82153553Stanimura /* Device interface */ 82253553Stanimura DEVMETHOD(device_probe , pcmcsa_probe ), 82353553Stanimura DEVMETHOD(device_attach, pcmcsa_attach), 82453553Stanimura 82553553Stanimura { 0, 0 }, 82653553Stanimura}; 82753553Stanimura 82853553Stanimurastatic driver_t pcmcsa_driver = { 82953553Stanimura "pcm", 83053553Stanimura pcmcsa_methods, 83153553Stanimura sizeof(snddev_info), 83253553Stanimura}; 83353553Stanimura 83453553Stanimurastatic devclass_t pcm_devclass; 83553553Stanimura 83653553StanimuraDRIVER_MODULE(pcmcsa, csa, pcmcsa_driver, pcm_devclass, 0, 0); 837