csapcm.c revision 78673
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 78673 2001-06-23 18:00:06Z cg $ 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 4377504Scg/* Buffer size on dma transfer. Fixed for CS416x. */ 4477504Scg#define CS461x_BUFFSIZE (4 * 1024) 4577504Scg 4677504Scg#define GOF_PER_SEC 200 4777504Scg 4853553Stanimura/* device private data */ 4953553Stanimurastruct csa_info; 5053553Stanimura 5153553Stanimurastruct csa_chinfo { 5253553Stanimura struct csa_info *parent; 5374763Scg struct pcm_channel *channel; 5474763Scg struct snd_dbuf *buffer; 5553553Stanimura int dir; 5677504Scg u_int32_t fmt, spd; 5755321Stanimura int dma; 5853553Stanimura}; 5953553Stanimura 6053553Stanimurastruct csa_info { 6153553Stanimura csa_res res; /* resource */ 6253553Stanimura void *ih; /* Interrupt cookie */ 6353553Stanimura bus_dma_tag_t parent_dmat; /* DMA tag */ 6455320Stanimura struct csa_bridgeinfo *binfo; /* The state of the parent. */ 6577504Scg struct csa_card *card; 6653553Stanimura 6777504Scg int active; 6853553Stanimura /* Contents of board's registers */ 6953553Stanimura u_long pfie; 7053553Stanimura u_long pctl; 7153553Stanimura u_long cctl; 7253553Stanimura struct csa_chinfo pch, rch; 7353553Stanimura}; 7453553Stanimura 7553553Stanimura/* -------------------------------------------------------------------- */ 7653553Stanimura 7753553Stanimura/* prototypes */ 7853553Stanimurastatic int csa_init(struct csa_info *); 7953553Stanimurastatic void csa_intr(void *); 8053553Stanimurastatic void csa_setplaysamplerate(csa_res *resp, u_long ulInRate); 8153553Stanimurastatic void csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate); 8253553Stanimurastatic void csa_startplaydma(struct csa_info *csa); 8353553Stanimurastatic void csa_startcapturedma(struct csa_info *csa); 8453553Stanimurastatic void csa_stopplaydma(struct csa_info *csa); 8553553Stanimurastatic void csa_stopcapturedma(struct csa_info *csa); 8653553Stanimurastatic int csa_startdsp(csa_res *resp); 8753553Stanimurastatic int csa_allocres(struct csa_info *scp, device_t dev); 8853553Stanimurastatic void csa_releaseres(struct csa_info *scp, device_t dev); 8953553Stanimura 9064881Scgstatic u_int32_t csa_playfmt[] = { 9164881Scg AFMT_U8, 9264881Scg AFMT_STEREO | AFMT_U8, 9364881Scg AFMT_S8, 9464881Scg AFMT_STEREO | AFMT_S8, 9564881Scg AFMT_S16_LE, 9664881Scg AFMT_STEREO | AFMT_S16_LE, 9764881Scg AFMT_S16_BE, 9864881Scg AFMT_STEREO | AFMT_S16_BE, 9964881Scg 0 10053553Stanimura}; 10174763Scgstatic struct pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0}; 10253553Stanimura 10364881Scgstatic u_int32_t csa_recfmt[] = { 10464881Scg AFMT_S16_LE, 10553553Stanimura AFMT_STEREO | AFMT_S16_LE, 10664881Scg 0 10753553Stanimura}; 10874763Scgstatic struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0}; 10953553Stanimura 11053553Stanimura/* -------------------------------------------------------------------- */ 11177504Scg 11277504Scgstatic int 11377504Scgcsa_active(struct csa_info *csa, int run) 11477504Scg{ 11577504Scg int old, go; 11677504Scg 11777504Scg old = csa->active; 11877504Scg csa->active += run; 11977504Scg 12077504Scg if ((csa->active == 0 && old == 1) || (csa->active == 1 && old == 0)) { 12177504Scg go = csa->active; 12277504Scg if (csa->card->active) 12377504Scg return csa->card->active(go); 12477504Scg } 12577504Scg return 0; 12677504Scg} 12777504Scg 12877504Scg/* -------------------------------------------------------------------- */ 12970134Scg/* ac97 codec */ 13053553Stanimura 13153553Stanimurastatic int 13270134Scgcsa_rdcd(kobj_t obj, void *devinfo, int regno) 13353553Stanimura{ 13470134Scg u_int32_t data; 13570134Scg struct csa_info *csa = (struct csa_info *)devinfo; 13653553Stanimura 13777504Scg csa_active(csa, 1); 13870134Scg if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data)) 13970134Scg data = 0; 14077504Scg csa_active(csa, -1); 14153553Stanimura 14270134Scg return data; 14353553Stanimura} 14453553Stanimura 14553553Stanimurastatic int 14670134Scgcsa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 14753553Stanimura{ 14870134Scg struct csa_info *csa = (struct csa_info *)devinfo; 14953553Stanimura 15077504Scg csa_active(csa, 1); 15170134Scg csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data); 15277504Scg csa_active(csa, -1); 15353553Stanimura 15453553Stanimura return 0; 15553553Stanimura} 15653553Stanimura 15770134Scgstatic kobj_method_t csa_ac97_methods[] = { 15870134Scg KOBJMETHOD(ac97_read, csa_rdcd), 15970134Scg KOBJMETHOD(ac97_write, csa_wrcd), 16070134Scg { 0, 0 } 16170134Scg}; 16270134ScgAC97_DECLARE(csa_ac97); 16353553Stanimura 16453553Stanimurastatic void 16553553Stanimuracsa_setplaysamplerate(csa_res *resp, u_long ulInRate) 16653553Stanimura{ 16753553Stanimura u_long ulTemp1, ulTemp2; 16853553Stanimura u_long ulPhiIncr; 16953553Stanimura u_long ulCorrectionPerGOF, ulCorrectionPerSec; 17053553Stanimura u_long ulOutRate; 17153553Stanimura 17253553Stanimura ulOutRate = 48000; 17353553Stanimura 17453553Stanimura /* 17553553Stanimura * Compute the values used to drive the actual sample rate conversion. 17653553Stanimura * The following formulas are being computed, using inline assembly 17753553Stanimura * since we need to use 64 bit arithmetic to compute the values: 17853553Stanimura * 17953553Stanimura * ulPhiIncr = floor((Fs,in * 2^26) / Fs,out) 18053553Stanimura * ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) / 18153553Stanimura * GOF_PER_SEC) 18253553Stanimura * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - 18353553Stanimura * GOF_PER_SEC * ulCorrectionPerGOF 18453553Stanimura * 18553553Stanimura * i.e. 18653553Stanimura * 18753553Stanimura * ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) 18853553Stanimura * ulCorrectionPerGOF:ulCorrectionPerSec = 18953553Stanimura * dividend:remainder(ulOther / GOF_PER_SEC) 19053553Stanimura */ 19153553Stanimura ulTemp1 = ulInRate << 16; 19253553Stanimura ulPhiIncr = ulTemp1 / ulOutRate; 19353553Stanimura ulTemp1 -= ulPhiIncr * ulOutRate; 19453553Stanimura ulTemp1 <<= 10; 19553553Stanimura ulPhiIncr <<= 10; 19653553Stanimura ulTemp2 = ulTemp1 / ulOutRate; 19753553Stanimura ulPhiIncr += ulTemp2; 19853553Stanimura ulTemp1 -= ulTemp2 * ulOutRate; 19953553Stanimura ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC; 20053553Stanimura ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC; 20153553Stanimura ulCorrectionPerSec = ulTemp1; 20253553Stanimura 20353553Stanimura /* 20453553Stanimura * Fill in the SampleRateConverter control block. 20553553Stanimura */ 20653553Stanimura csa_writemem(resp, BA1_PSRC, ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF)); 20753553Stanimura csa_writemem(resp, BA1_PPI, ulPhiIncr); 20853553Stanimura} 20953553Stanimura 21053553Stanimurastatic void 21153553Stanimuracsa_setcapturesamplerate(csa_res *resp, u_long ulOutRate) 21253553Stanimura{ 21353553Stanimura u_long ulPhiIncr, ulCoeffIncr, ulTemp1, ulTemp2; 21453553Stanimura u_long ulCorrectionPerGOF, ulCorrectionPerSec, ulInitialDelay; 21553553Stanimura u_long dwFrameGroupLength, dwCnt; 21653553Stanimura u_long ulInRate; 21753553Stanimura 21853553Stanimura ulInRate = 48000; 21953553Stanimura 22053553Stanimura /* 22153553Stanimura * We can only decimate by up to a factor of 1/9th the hardware rate. 22253553Stanimura * Return an error if an attempt is made to stray outside that limit. 22353553Stanimura */ 22453553Stanimura if((ulOutRate * 9) < ulInRate) 22553553Stanimura return; 22653553Stanimura 22753553Stanimura /* 22853553Stanimura * We can not capture at at rate greater than the Input Rate (48000). 22953553Stanimura * Return an error if an attempt is made to stray outside that limit. 23053553Stanimura */ 23153553Stanimura if(ulOutRate > ulInRate) 23253553Stanimura return; 23353553Stanimura 23453553Stanimura /* 23553553Stanimura * Compute the values used to drive the actual sample rate conversion. 23653553Stanimura * The following formulas are being computed, using inline assembly 23753553Stanimura * since we need to use 64 bit arithmetic to compute the values: 23853553Stanimura * 23953553Stanimura * ulCoeffIncr = -floor((Fs,out * 2^23) / Fs,in) 24053553Stanimura * ulPhiIncr = floor((Fs,in * 2^26) / Fs,out) 24153553Stanimura * ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) / 24253553Stanimura * GOF_PER_SEC) 24353553Stanimura * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - 24453553Stanimura * GOF_PER_SEC * ulCorrectionPerGOF 24553553Stanimura * ulInitialDelay = ceil((24 * Fs,in) / Fs,out) 24653553Stanimura * 24753553Stanimura * i.e. 24853553Stanimura * 24953553Stanimura * ulCoeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) 25053553Stanimura * ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) 25153553Stanimura * ulCorrectionPerGOF:ulCorrectionPerSec = 25253553Stanimura * dividend:remainder(ulOther / GOF_PER_SEC) 25353553Stanimura * ulInitialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) 25453553Stanimura */ 25553553Stanimura ulTemp1 = ulOutRate << 16; 25653553Stanimura ulCoeffIncr = ulTemp1 / ulInRate; 25753553Stanimura ulTemp1 -= ulCoeffIncr * ulInRate; 25853553Stanimura ulTemp1 <<= 7; 25953553Stanimura ulCoeffIncr <<= 7; 26053553Stanimura ulCoeffIncr += ulTemp1 / ulInRate; 26153553Stanimura ulCoeffIncr ^= 0xFFFFFFFF; 26253553Stanimura ulCoeffIncr++; 26353553Stanimura ulTemp1 = ulInRate << 16; 26453553Stanimura ulPhiIncr = ulTemp1 / ulOutRate; 26553553Stanimura ulTemp1 -= ulPhiIncr * ulOutRate; 26653553Stanimura ulTemp1 <<= 10; 26753553Stanimura ulPhiIncr <<= 10; 26853553Stanimura ulTemp2 = ulTemp1 / ulOutRate; 26953553Stanimura ulPhiIncr += ulTemp2; 27053553Stanimura ulTemp1 -= ulTemp2 * ulOutRate; 27153553Stanimura ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC; 27253553Stanimura ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC; 27353553Stanimura ulCorrectionPerSec = ulTemp1; 27453553Stanimura ulInitialDelay = ((ulInRate * 24) + ulOutRate - 1) / ulOutRate; 27553553Stanimura 27653553Stanimura /* 27753553Stanimura * Fill in the VariDecimate control block. 27853553Stanimura */ 27956249Scg csa_writemem(resp, BA1_CSRC, 28053553Stanimura ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF)); 28153553Stanimura csa_writemem(resp, BA1_CCI, ulCoeffIncr); 28256249Scg csa_writemem(resp, BA1_CD, 28353553Stanimura (((BA1_VARIDEC_BUF_1 + (ulInitialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); 28453553Stanimura csa_writemem(resp, BA1_CPI, ulPhiIncr); 28553553Stanimura 28653553Stanimura /* 28753553Stanimura * Figure out the frame group length for the write back task. Basically, 28853553Stanimura * this is just the factors of 24000 (2^6*3*5^3) that are not present in 28953553Stanimura * the output sample rate. 29053553Stanimura */ 29153553Stanimura dwFrameGroupLength = 1; 29253553Stanimura for(dwCnt = 2; dwCnt <= 64; dwCnt *= 2) 29353553Stanimura { 29453553Stanimura if(((ulOutRate / dwCnt) * dwCnt) != 29553553Stanimura ulOutRate) 29653553Stanimura { 29753553Stanimura dwFrameGroupLength *= 2; 29853553Stanimura } 29953553Stanimura } 30053553Stanimura if(((ulOutRate / 3) * 3) != 30153553Stanimura ulOutRate) 30253553Stanimura { 30353553Stanimura dwFrameGroupLength *= 3; 30453553Stanimura } 30553553Stanimura for(dwCnt = 5; dwCnt <= 125; dwCnt *= 5) 30653553Stanimura { 30753553Stanimura if(((ulOutRate / dwCnt) * dwCnt) != 30853553Stanimura ulOutRate) 30953553Stanimura { 31053553Stanimura dwFrameGroupLength *= 5; 31153553Stanimura } 31253553Stanimura } 31353553Stanimura 31453553Stanimura /* 31553553Stanimura * Fill in the WriteBack control block. 31653553Stanimura */ 31753553Stanimura csa_writemem(resp, BA1_CFG1, dwFrameGroupLength); 31853553Stanimura csa_writemem(resp, BA1_CFG2, (0x00800000 | dwFrameGroupLength)); 31953553Stanimura csa_writemem(resp, BA1_CCST, 0x0000FFFF); 32053553Stanimura csa_writemem(resp, BA1_CSPB, ((65536 * ulOutRate) / 24000)); 32153553Stanimura csa_writemem(resp, (BA1_CSPB + 4), 0x0000FFFF); 32253553Stanimura} 32353553Stanimura 32453553Stanimurastatic void 32553553Stanimuracsa_startplaydma(struct csa_info *csa) 32653553Stanimura{ 32753553Stanimura csa_res *resp; 32853553Stanimura u_long ul; 32953553Stanimura 33055321Stanimura if (!csa->pch.dma) { 33155321Stanimura resp = &csa->res; 33255321Stanimura ul = csa_readmem(resp, BA1_PCTL); 33355321Stanimura ul &= 0x0000ffff; 33455321Stanimura csa_writemem(resp, BA1_PCTL, ul | csa->pctl); 33555321Stanimura csa_writemem(resp, BA1_PVOL, 0x80008000); 33655321Stanimura csa->pch.dma = 1; 33755321Stanimura } 33853553Stanimura} 33953553Stanimura 34053553Stanimurastatic void 34153553Stanimuracsa_startcapturedma(struct csa_info *csa) 34253553Stanimura{ 34353553Stanimura csa_res *resp; 34453553Stanimura u_long ul; 34553553Stanimura 34655321Stanimura if (!csa->rch.dma) { 34755321Stanimura resp = &csa->res; 34855321Stanimura ul = csa_readmem(resp, BA1_CCTL); 34955321Stanimura ul &= 0xffff0000; 35055321Stanimura csa_writemem(resp, BA1_CCTL, ul | csa->cctl); 35155321Stanimura csa_writemem(resp, BA1_CVOL, 0x80008000); 35255321Stanimura csa->rch.dma = 1; 35355321Stanimura } 35453553Stanimura} 35553553Stanimura 35653553Stanimurastatic void 35753553Stanimuracsa_stopplaydma(struct csa_info *csa) 35853553Stanimura{ 35953553Stanimura csa_res *resp; 36053553Stanimura u_long ul; 36153553Stanimura 36255321Stanimura if (csa->pch.dma) { 36355321Stanimura resp = &csa->res; 36455321Stanimura ul = csa_readmem(resp, BA1_PCTL); 36555321Stanimura csa->pctl = ul & 0xffff0000; 36655321Stanimura csa_writemem(resp, BA1_PCTL, ul & 0x0000ffff); 36755321Stanimura csa_writemem(resp, BA1_PVOL, 0xffffffff); 36856427Stanimura csa->pch.dma = 0; 36955320Stanimura 37056427Stanimura /* 37156427Stanimura * The bitwise pointer of the serial FIFO in the DSP 37256427Stanimura * seems to make an error upon starting or stopping the 37356427Stanimura * DSP. Clear the FIFO and correct the pointer if we 37456427Stanimura * are not capturing. 37556427Stanimura */ 37656427Stanimura if (!csa->rch.dma) { 37756427Stanimura csa_clearserialfifos(resp); 37856427Stanimura csa_writeio(resp, BA0_SERBSP, 0); 37956427Stanimura } 38055321Stanimura } 38153553Stanimura} 38253553Stanimura 38353553Stanimurastatic void 38453553Stanimuracsa_stopcapturedma(struct csa_info *csa) 38553553Stanimura{ 38653553Stanimura csa_res *resp; 38753553Stanimura u_long ul; 38853553Stanimura 38955321Stanimura if (csa->rch.dma) { 39055321Stanimura resp = &csa->res; 39155321Stanimura ul = csa_readmem(resp, BA1_CCTL); 39255321Stanimura csa->cctl = ul & 0x0000ffff; 39355321Stanimura csa_writemem(resp, BA1_CCTL, ul & 0xffff0000); 39455321Stanimura csa_writemem(resp, BA1_CVOL, 0xffffffff); 39555321Stanimura csa->rch.dma = 0; 39656427Stanimura 39756427Stanimura /* 39856427Stanimura * The bitwise pointer of the serial FIFO in the DSP 39956427Stanimura * seems to make an error upon starting or stopping the 40056427Stanimura * DSP. Clear the FIFO and correct the pointer if we 40156427Stanimura * are not playing. 40256427Stanimura */ 40356427Stanimura if (!csa->pch.dma) { 40456427Stanimura csa_clearserialfifos(resp); 40556427Stanimura csa_writeio(resp, BA0_SERBSP, 0); 40656427Stanimura } 40755321Stanimura } 40853553Stanimura} 40953553Stanimura 41053553Stanimurastatic int 41153553Stanimuracsa_startdsp(csa_res *resp) 41253553Stanimura{ 41353553Stanimura int i; 41453553Stanimura u_long ul; 41553553Stanimura 41653553Stanimura /* 41753553Stanimura * Set the frame timer to reflect the number of cycles per frame. 41853553Stanimura */ 41953553Stanimura csa_writemem(resp, BA1_FRMT, 0xadf); 42053553Stanimura 42153553Stanimura /* 42253553Stanimura * Turn on the run, run at frame, and DMA enable bits in the local copy of 42353553Stanimura * the SP control register. 42453553Stanimura */ 42553553Stanimura csa_writemem(resp, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN); 42653553Stanimura 42753553Stanimura /* 42853553Stanimura * Wait until the run at frame bit resets itself in the SP control 42953553Stanimura * register. 43053553Stanimura */ 43153553Stanimura ul = 0; 43253553Stanimura for (i = 0 ; i < 25 ; i++) { 43353553Stanimura /* 43453553Stanimura * Wait a little bit, so we don't issue PCI reads too frequently. 43553553Stanimura */ 43677504Scg DELAY(50); 43753553Stanimura /* 43853553Stanimura * Fetch the current value of the SP status register. 43953553Stanimura */ 44053553Stanimura ul = csa_readmem(resp, BA1_SPCR); 44153553Stanimura 44253553Stanimura /* 44353553Stanimura * If the run at frame bit has reset, then stop waiting. 44453553Stanimura */ 44553553Stanimura if((ul & SPCR_RUNFR) == 0) 44653553Stanimura break; 44753553Stanimura } 44853553Stanimura /* 44953553Stanimura * If the run at frame bit never reset, then return an error. 45053553Stanimura */ 45153553Stanimura if((ul & SPCR_RUNFR) != 0) 45253553Stanimura return (EAGAIN); 45353553Stanimura 45453553Stanimura return (0); 45553553Stanimura} 45653553Stanimura 45777504Scgstatic int 45877504Scgcsa_setupchan(struct csa_chinfo *ch) 45977504Scg{ 46077504Scg struct csa_info *csa = ch->parent; 46177504Scg csa_res *resp = &csa->res; 46277504Scg u_long pdtc, tmp; 46377504Scg 46477504Scg if (ch->dir == PCMDIR_PLAY) { 46577504Scg /* direction */ 46677504Scg csa_writemem(resp, BA1_PBA, vtophys(sndbuf_getbuf(ch->buffer))); 46777504Scg 46877504Scg /* format */ 46977504Scg csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; 47077504Scg if (!(ch->fmt & AFMT_SIGNED)) 47177504Scg csa->pfie |= 0x8000; 47277504Scg if (ch->fmt & AFMT_BIGENDIAN) 47377504Scg csa->pfie |= 0x4000; 47477504Scg if (!(ch->fmt & AFMT_STEREO)) 47577504Scg csa->pfie |= 0x2000; 47677504Scg if (ch->fmt & AFMT_8BIT) 47777504Scg csa->pfie |= 0x1000; 47877504Scg csa_writemem(resp, BA1_PFIE, csa->pfie); 47977504Scg 48077504Scg tmp = 4; 48177504Scg if (ch->fmt & AFMT_16BIT) 48277504Scg tmp <<= 1; 48377504Scg if (ch->fmt & AFMT_STEREO) 48477504Scg tmp <<= 1; 48577504Scg tmp--; 48677504Scg 48777504Scg pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000001ff; 48877504Scg pdtc |= tmp; 48977504Scg csa_writemem(resp, BA1_PDTC, pdtc); 49077504Scg 49177504Scg /* rate */ 49277504Scg csa_setplaysamplerate(resp, ch->spd); 49377504Scg } else if (ch->dir == PCMDIR_REC) { 49477504Scg /* direction */ 49577504Scg csa_writemem(resp, BA1_CBA, vtophys(sndbuf_getbuf(ch->buffer))); 49677504Scg 49777504Scg /* format */ 49877504Scg csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 49977504Scg 50077504Scg /* rate */ 50177504Scg csa_setcapturesamplerate(resp, ch->spd); 50277504Scg } 50377504Scg return 0; 50477504Scg} 50577504Scg 50670134Scg/* -------------------------------------------------------------------- */ 50770134Scg/* channel interface */ 50870134Scg 50970134Scgstatic void * 51074763Scgcsachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 51170134Scg{ 51270134Scg struct csa_info *csa = devinfo; 51370134Scg struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch; 51470134Scg 51570134Scg ch->parent = csa; 51670134Scg ch->channel = c; 51770134Scg ch->buffer = b; 51877504Scg ch->dir = dir; 51970291Scg if (sndbuf_alloc(ch->buffer, csa->parent_dmat, CS461x_BUFFSIZE) == -1) return NULL; 52070134Scg return ch; 52170134Scg} 52270134Scg 52353553Stanimurastatic int 52470134Scgcsachan_setformat(kobj_t obj, void *data, u_int32_t format) 52570134Scg{ 52670134Scg struct csa_chinfo *ch = data; 52770134Scg 52870134Scg ch->fmt = format; 52970134Scg return 0; 53070134Scg} 53170134Scg 53270134Scgstatic int 53370134Scgcsachan_setspeed(kobj_t obj, void *data, u_int32_t speed) 53470134Scg{ 53570134Scg struct csa_chinfo *ch = data; 53670134Scg 53777504Scg ch->spd = speed; 53877504Scg return ch->spd; /* XXX calc real speed */ 53970134Scg} 54070134Scg 54170134Scgstatic int 54270134Scgcsachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 54370134Scg{ 54470291Scg return CS461x_BUFFSIZE / 2; 54570134Scg} 54670134Scg 54770134Scgstatic int 54870134Scgcsachan_trigger(kobj_t obj, void *data, int go) 54970134Scg{ 55070134Scg struct csa_chinfo *ch = data; 55170134Scg struct csa_info *csa = ch->parent; 55270134Scg 55370134Scg if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 55470134Scg return 0; 55570134Scg 55677504Scg if (go == PCMTRIG_START) { 55777504Scg csa_active(csa, 1); 55877504Scg csa_setupchan(ch); 55977504Scg if (ch->dir == PCMDIR_PLAY) 56070134Scg csa_startplaydma(csa); 56170134Scg else 56277504Scg csa_startcapturedma(csa); 56377504Scg } else { 56477504Scg if (ch->dir == PCMDIR_PLAY) 56570134Scg csa_stopplaydma(csa); 56670134Scg else 56770134Scg csa_stopcapturedma(csa); 56877504Scg csa_active(csa, -1); 56970134Scg } 57070134Scg return 0; 57170134Scg} 57270134Scg 57370134Scgstatic int 57470134Scgcsachan_getptr(kobj_t obj, void *data) 57570134Scg{ 57670134Scg struct csa_chinfo *ch = data; 57770134Scg struct csa_info *csa = ch->parent; 57870134Scg csa_res *resp; 57953553Stanimura int ptr; 58053553Stanimura 58153553Stanimura resp = &csa->res; 58253553Stanimura 58353553Stanimura if (ch->dir == PCMDIR_PLAY) { 58470291Scg ptr = csa_readmem(resp, BA1_PBA) - vtophys(sndbuf_getbuf(ch->buffer)); 58553553Stanimura if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0) 58653553Stanimura ptr >>= 1; 58753553Stanimura } else { 58870291Scg ptr = csa_readmem(resp, BA1_CBA) - vtophys(sndbuf_getbuf(ch->buffer)); 58953553Stanimura if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0) 59053553Stanimura ptr >>= 1; 59153553Stanimura } 59253553Stanimura 59353553Stanimura return (ptr); 59453553Stanimura} 59553553Stanimura 59674763Scgstatic struct pcmchan_caps * 59770134Scgcsachan_getcaps(kobj_t obj, void *data) 59853553Stanimura{ 59953553Stanimura struct csa_chinfo *ch = data; 60053553Stanimura return (ch->dir == PCMDIR_PLAY)? &csa_playcaps : &csa_reccaps; 60153553Stanimura} 60253553Stanimura 60370134Scgstatic kobj_method_t csachan_methods[] = { 60470134Scg KOBJMETHOD(channel_init, csachan_init), 60570134Scg KOBJMETHOD(channel_setformat, csachan_setformat), 60670134Scg KOBJMETHOD(channel_setspeed, csachan_setspeed), 60770134Scg KOBJMETHOD(channel_setblocksize, csachan_setblocksize), 60870134Scg KOBJMETHOD(channel_trigger, csachan_trigger), 60970134Scg KOBJMETHOD(channel_getptr, csachan_getptr), 61070134Scg KOBJMETHOD(channel_getcaps, csachan_getcaps), 61170134Scg { 0, 0 } 61270134Scg}; 61370134ScgCHANNEL_DECLARE(csachan); 61470134Scg 61570134Scg/* -------------------------------------------------------------------- */ 61653553Stanimura/* The interrupt handler */ 61753553Stanimurastatic void 61877504Scgcsa_intr(void *p) 61953553Stanimura{ 62053553Stanimura struct csa_info *csa = p; 62153553Stanimura 62255320Stanimura if ((csa->binfo->hisr & HISR_VC0) != 0) 62353553Stanimura chn_intr(csa->pch.channel); 62455320Stanimura if ((csa->binfo->hisr & HISR_VC1) != 0) 62553553Stanimura chn_intr(csa->rch.channel); 62653553Stanimura} 62753553Stanimura 62853553Stanimura/* -------------------------------------------------------------------- */ 62953553Stanimura 63053553Stanimura/* 63153553Stanimura * Probe and attach the card 63253553Stanimura */ 63353553Stanimura 63453553Stanimurastatic int 63553553Stanimuracsa_init(struct csa_info *csa) 63653553Stanimura{ 63753553Stanimura csa_res *resp; 63853553Stanimura 63953553Stanimura resp = &csa->res; 64053553Stanimura 64153553Stanimura csa->pfie = 0; 64253553Stanimura csa_stopplaydma(csa); 64353553Stanimura csa_stopcapturedma(csa); 64453553Stanimura 64577504Scg if (csa_startdsp(resp)) 64677504Scg return (1); 64777504Scg 64853553Stanimura /* Crank up the power on the DAC and ADC. */ 64953553Stanimura csa_setplaysamplerate(resp, 8000); 65053553Stanimura csa_setcapturesamplerate(resp, 8000); 65153553Stanimura 65253553Stanimura return 0; 65353553Stanimura} 65453553Stanimura 65553553Stanimura/* Allocates resources. */ 65653553Stanimurastatic int 65753553Stanimuracsa_allocres(struct csa_info *csa, device_t dev) 65853553Stanimura{ 65953553Stanimura csa_res *resp; 66053553Stanimura 66153553Stanimura resp = &csa->res; 66253553Stanimura if (resp->io == NULL) { 66377504Scg resp->io = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->io_rid, 0, ~0, 1, RF_ACTIVE); 66453553Stanimura if (resp->io == NULL) 66553553Stanimura return (1); 66653553Stanimura } 66753553Stanimura if (resp->mem == NULL) { 66877504Scg resp->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &resp->mem_rid, 0, ~0, 1, RF_ACTIVE); 66953553Stanimura if (resp->mem == NULL) 67053553Stanimura return (1); 67153553Stanimura } 67253553Stanimura if (resp->irq == NULL) { 67353553Stanimura resp->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &resp->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 67453553Stanimura if (resp->irq == NULL) 67553553Stanimura return (1); 67653553Stanimura } 67753553Stanimura if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/CS461x_BUFFSIZE, /*boundary*/CS461x_BUFFSIZE, 67853553Stanimura /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 67953553Stanimura /*highaddr*/BUS_SPACE_MAXADDR, 68053553Stanimura /*filter*/NULL, /*filterarg*/NULL, 68153553Stanimura /*maxsize*/CS461x_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 68253553Stanimura /*flags*/0, &csa->parent_dmat) != 0) 68353553Stanimura return (1); 68453553Stanimura 68553553Stanimura return (0); 68653553Stanimura} 68753553Stanimura 68853553Stanimura/* Releases resources. */ 68953553Stanimurastatic void 69053553Stanimuracsa_releaseres(struct csa_info *csa, device_t dev) 69153553Stanimura{ 69253553Stanimura csa_res *resp; 69353553Stanimura 69453553Stanimura resp = &csa->res; 69553553Stanimura if (resp->irq != NULL) { 69665644Scg if (csa->ih) 69765644Scg bus_teardown_intr(dev, resp->irq, csa->ih); 69853553Stanimura bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq); 69953553Stanimura resp->irq = NULL; 70053553Stanimura } 70153553Stanimura if (resp->io != NULL) { 70253553Stanimura bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io); 70353553Stanimura resp->io = NULL; 70453553Stanimura } 70553553Stanimura if (resp->mem != NULL) { 70653553Stanimura bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem); 70753553Stanimura resp->mem = NULL; 70853553Stanimura } 70965644Scg if (csa->parent_dmat != NULL) { 71065644Scg bus_dma_tag_destroy(csa->parent_dmat); 71165644Scg csa->parent_dmat = NULL; 71265644Scg } 71365644Scg if (csa != NULL) { 71465644Scg free(csa, M_DEVBUF); 71565644Scg csa = NULL; 71665644Scg } 71753553Stanimura} 71853553Stanimura 71953553Stanimurastatic int 72053553Stanimurapcmcsa_probe(device_t dev) 72153553Stanimura{ 72253553Stanimura char *s; 72353553Stanimura struct sndcard_func *func; 72453553Stanimura 72553553Stanimura /* The parent device has already been probed. */ 72653553Stanimura 72753553Stanimura func = device_get_ivars(dev); 72853553Stanimura if (func == NULL || func->func != SCF_PCM) 72953553Stanimura return (ENXIO); 73053553Stanimura 73153553Stanimura s = "CS461x PCM Audio"; 73253553Stanimura 73353553Stanimura device_set_desc(dev, s); 73453553Stanimura return (0); 73553553Stanimura} 73653553Stanimura 73753553Stanimurastatic int 73853553Stanimurapcmcsa_attach(device_t dev) 73953553Stanimura{ 74053553Stanimura struct csa_info *csa; 74153553Stanimura csa_res *resp; 74253553Stanimura int unit; 74353553Stanimura char status[SND_STATUSLEN]; 74453553Stanimura struct ac97_info *codec; 74555320Stanimura struct sndcard_func *func; 74653553Stanimura 74778564Sgreid csa = malloc(sizeof(*csa), M_DEVBUF, M_NOWAIT | M_ZERO); 74853553Stanimura if (csa == NULL) 74953553Stanimura return (ENOMEM); 75053553Stanimura unit = device_get_unit(dev); 75155320Stanimura func = device_get_ivars(dev); 75255320Stanimura csa->binfo = func->varinfo; 75355321Stanimura /* 75455321Stanimura * Fake the status of DMA so that the initial value of 75555321Stanimura * PCTL and CCTL can be stored into csa->pctl and csa->cctl, 75655321Stanimura * respectively. 75755321Stanimura */ 75855321Stanimura csa->pch.dma = csa->rch.dma = 1; 75977504Scg csa->active = 0; 76077504Scg csa->card = csa->binfo->card; 76153553Stanimura 76253553Stanimura /* Allocate the resources. */ 76353553Stanimura resp = &csa->res; 76477504Scg resp->io_rid = PCIR_MAPS; 76577504Scg resp->mem_rid = PCIR_MAPS + 4; 76653553Stanimura resp->irq_rid = 0; 76753553Stanimura if (csa_allocres(csa, dev)) { 76853553Stanimura csa_releaseres(csa, dev); 76953553Stanimura return (ENXIO); 77053553Stanimura } 77153553Stanimura 77277504Scg csa_active(csa, 1); 77353553Stanimura if (csa_init(csa)) { 77453553Stanimura csa_releaseres(csa, dev); 77553553Stanimura return (ENXIO); 77653553Stanimura } 77770134Scg codec = AC97_CREATE(dev, csa, csa_ac97); 77865644Scg if (codec == NULL) { 77965644Scg csa_releaseres(csa, dev); 78053553Stanimura return (ENXIO); 78165644Scg } 78278673Scg if (csa->card->inv_eapd) 78378673Scg ac97_setflags(codec, AC97_F_EAPD_INV); 78470134Scg if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) { 78565644Scg ac97_destroy(codec); 78665644Scg csa_releaseres(csa, dev); 78758905Scg return (ENXIO); 78865644Scg } 78953553Stanimura 79053553Stanimura snprintf(status, SND_STATUSLEN, "at irq %ld", rman_get_start(resp->irq)); 79153553Stanimura 79253553Stanimura /* Enable interrupt. */ 79377504Scg if (snd_setup_intr(dev, resp->irq, INTR_MPSAFE, csa_intr, csa, &csa->ih)) { 79465644Scg ac97_destroy(codec); 79553553Stanimura csa_releaseres(csa, dev); 79653553Stanimura return (ENXIO); 79753553Stanimura } 79853553Stanimura csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f); 79953553Stanimura csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 80077504Scg csa_active(csa, -1); 80153553Stanimura 80253553Stanimura if (pcm_register(dev, csa, 1, 1)) { 80365644Scg ac97_destroy(codec); 80453553Stanimura csa_releaseres(csa, dev); 80553553Stanimura return (ENXIO); 80653553Stanimura } 80770134Scg pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa); 80870134Scg pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa); 80953553Stanimura pcm_setstatus(dev, status); 81053553Stanimura 81153553Stanimura return (0); 81253553Stanimura} 81353553Stanimura 81465644Scgstatic int 81565644Scgpcmcsa_detach(device_t dev) 81665644Scg{ 81765644Scg int r; 81865644Scg struct csa_info *csa; 81965644Scg 82065644Scg r = pcm_unregister(dev); 82165644Scg if (r) 82265644Scg return r; 82365644Scg 82465644Scg csa = pcm_getdevinfo(dev); 82565644Scg csa_releaseres(csa, dev); 82665644Scg 82765644Scg return 0; 82865644Scg} 82965644Scg 83053553Stanimurastatic device_method_t pcmcsa_methods[] = { 83153553Stanimura /* Device interface */ 83253553Stanimura DEVMETHOD(device_probe , pcmcsa_probe ), 83353553Stanimura DEVMETHOD(device_attach, pcmcsa_attach), 83465644Scg DEVMETHOD(device_detach, pcmcsa_detach), 83553553Stanimura 83653553Stanimura { 0, 0 }, 83753553Stanimura}; 83853553Stanimura 83953553Stanimurastatic driver_t pcmcsa_driver = { 84053553Stanimura "pcm", 84153553Stanimura pcmcsa_methods, 84274763Scg sizeof(struct snddev_info), 84353553Stanimura}; 84453553Stanimura 84562483ScgDRIVER_MODULE(snd_csapcm, csa, pcmcsa_driver, pcm_devclass, 0, 0); 84662483ScgMODULE_DEPEND(snd_csapcm, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 84762483ScgMODULE_DEPEND(snd_csapcm, snd_csa, 1, 1, 1); 84862483ScgMODULE_VERSION(snd_csapcm, 1); 849