csapcm.c revision 256281
1176667Sjfv/*- 2176667Sjfv * Copyright (c) 1999 Seigo Tanimura 3220375Sjfv * All rights reserved. 4176667Sjfv * 5176667Sjfv * Portions of this source are based on cwcealdr.cpp and dhwiface.cpp in 6176667Sjfv * cwcealdr1.zip, the sample sources by Crystal Semiconductor. 7176667Sjfv * Copyright (c) 1996-1998 Crystal Semiconductor Corp. 8176667Sjfv * 9176667Sjfv * Redistribution and use in source and binary forms, with or without 10176667Sjfv * modification, are permitted provided that the following conditions 11176667Sjfv * are met: 12176667Sjfv * 1. Redistributions of source code must retain the above copyright 13176667Sjfv * notice, this list of conditions and the following disclaimer. 14176667Sjfv * 2. Redistributions in binary form must reproduce the above copyright 15176667Sjfv * notice, this list of conditions and the following disclaimer in the 16176667Sjfv * documentation and/or other materials provided with the distribution. 17176667Sjfv * 18176667Sjfv * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19176667Sjfv * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20176667Sjfv * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21176667Sjfv * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22176667Sjfv * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23176667Sjfv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24176667Sjfv * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25176667Sjfv * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26176667Sjfv * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27176667Sjfv * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28176667Sjfv * SUCH DAMAGE. 29176667Sjfv */ 30176667Sjfv 31176667Sjfv#ifdef HAVE_KERNEL_OPTION_HEADERS 32176667Sjfv#include "opt_snd.h" 33176667Sjfv#endif 34176667Sjfv 35194865Sjfv#include <dev/sound/pcm/sound.h> 36176667Sjfv#include <dev/sound/pcm/ac97.h> 37176667Sjfv#include <dev/sound/chip.h> 38195691Sbz#include <dev/sound/pci/csareg.h> 39223350Sjfv#include <dev/sound/pci/csavar.h> 40203354Sjfv 41176667Sjfv#include <dev/pci/pcireg.h> 42176667Sjfv#include <dev/pci/pcivar.h> 43176667Sjfv 44176667SjfvSND_DECLARE_FILE("$FreeBSD: stable/10/sys/dev/sound/pci/csapcm.c 193640 2009-06-07 19:12:08Z ariff $"); 45194865Sjfv 46194865Sjfv/* Buffer size on dma transfer. Fixed for CS416x. */ 47194865Sjfv#define CS461x_BUFFSIZE (4 * 1024) 48176667Sjfv 49176667Sjfv#define GOF_PER_SEC 200 50176667Sjfv 51176667Sjfv/* device private data */ 52176667Sjfvstruct csa_info; 53176667Sjfv 54176667Sjfvstruct csa_chinfo { 55176667Sjfv struct csa_info *parent; 56176667Sjfv struct pcm_channel *channel; 57176667Sjfv struct snd_dbuf *buffer; 58176667Sjfv int dir; 59176667Sjfv u_int32_t fmt, spd; 60181027Sjfv int dma; 61176667Sjfv}; 62194865Sjfv 63194865Sjfvstruct csa_info { 64176667Sjfv csa_res res; /* resource */ 65176667Sjfv void *ih; /* Interrupt cookie */ 66176667Sjfv bus_dma_tag_t parent_dmat; /* DMA tag */ 67176667Sjfv struct csa_bridgeinfo *binfo; /* The state of the parent. */ 68176667Sjfv struct csa_card *card; 69176667Sjfv 70176667Sjfv int active; 71176667Sjfv /* Contents of board's registers */ 72176667Sjfv u_long pfie; 73176667Sjfv u_long pctl; 74176667Sjfv u_long cctl; 75176667Sjfv struct csa_chinfo pch, rch; 76176667Sjfv u_int32_t ac97[CS461x_AC97_NUMBER_RESTORE_REGS]; 77176667Sjfv u_int32_t ac97_powerdown; 78176667Sjfv u_int32_t ac97_general_purpose; 79176667Sjfv}; 80176667Sjfv 81176667Sjfv/* -------------------------------------------------------------------- */ 82176667Sjfv 83181035Sps/* prototypes */ 84176667Sjfvstatic int csa_init(struct csa_info *); 85176667Sjfvstatic void csa_intr(void *); 86176667Sjfvstatic void csa_setplaysamplerate(csa_res *resp, u_long ulInRate); 87206001Smariusstatic void csa_setcapturesamplerate(csa_res *resp, u_long ulOutRate); 88176667Sjfvstatic void csa_startplaydma(struct csa_info *csa); 89176667Sjfvstatic void csa_startcapturedma(struct csa_info *csa); 90176667Sjfvstatic void csa_stopplaydma(struct csa_info *csa); 91176667Sjfvstatic void csa_stopcapturedma(struct csa_info *csa); 92176667Sjfvstatic int csa_startdsp(csa_res *resp); 93176667Sjfvstatic int csa_stopdsp(csa_res *resp); 94176667Sjfvstatic int csa_allocres(struct csa_info *scp, device_t dev); 95176667Sjfvstatic void csa_releaseres(struct csa_info *scp, device_t dev); 96176667Sjfvstatic void csa_ac97_suspend(struct csa_info *csa); 97176667Sjfvstatic void csa_ac97_resume(struct csa_info *csa); 98176667Sjfv 99176667Sjfvstatic u_int32_t csa_playfmt[] = { 100176667Sjfv SND_FORMAT(AFMT_U8, 1, 0), 101176667Sjfv SND_FORMAT(AFMT_U8, 2, 0), 102176667Sjfv SND_FORMAT(AFMT_S8, 1, 0), 103223350Sjfv SND_FORMAT(AFMT_S8, 2, 0), 104176667Sjfv SND_FORMAT(AFMT_S16_LE, 1, 0), 105176667Sjfv SND_FORMAT(AFMT_S16_LE, 2, 0), 106176667Sjfv SND_FORMAT(AFMT_S16_BE, 1, 0), 107176667Sjfv SND_FORMAT(AFMT_S16_BE, 2, 0), 108176667Sjfv 0 109176667Sjfv}; 110176667Sjfvstatic struct pcmchan_caps csa_playcaps = {8000, 48000, csa_playfmt, 0}; 111176667Sjfv 112176667Sjfvstatic u_int32_t csa_recfmt[] = { 113176667Sjfv SND_FORMAT(AFMT_S16_LE, 1, 0), 114176667Sjfv SND_FORMAT(AFMT_S16_LE, 2, 0), 115176667Sjfv 0 116176667Sjfv}; 117176667Sjfvstatic struct pcmchan_caps csa_reccaps = {11025, 48000, csa_recfmt, 0}; 118176667Sjfv 119176667Sjfv/* -------------------------------------------------------------------- */ 120176667Sjfv 121176667Sjfvstatic int 122176667Sjfvcsa_active(struct csa_info *csa, int run) 123181027Sjfv{ 124190872Sjfv int old; 125200243Sjfv 126181027Sjfv old = csa->active; 127181027Sjfv csa->active += run; 128194865Sjfv 129194865Sjfv if ((csa->active > 1) || (csa->active < -1)) 130190872Sjfv csa->active = 0; 131190872Sjfv if (csa->card->active) 132213234Sjfv return (csa->card->active(!(csa->active && old))); 133213234Sjfv 134209611Sjfv return 0; 135200243Sjfv} 136200243Sjfv 137200243Sjfv/* -------------------------------------------------------------------- */ 138200243Sjfv/* ac97 codec */ 139200243Sjfv 140200243Sjfvstatic int 141215781Sjfvcsa_rdcd(kobj_t obj, void *devinfo, int regno) 142215781Sjfv{ 143215781Sjfv u_int32_t data; 144215781Sjfv struct csa_info *csa = (struct csa_info *)devinfo; 145218530Sjfv 146218530Sjfv csa_active(csa, 1); 147218530Sjfv if (csa_readcodec(&csa->res, regno + BA0_AC97_RESET, &data)) 148218530Sjfv data = 0; 149218530Sjfv csa_active(csa, -1); 150218530Sjfv 151218530Sjfv return data; 152218530Sjfv} 153176667Sjfv 154176667Sjfvstatic int 155176667Sjfvcsa_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 156176667Sjfv{ 157176667Sjfv struct csa_info *csa = (struct csa_info *)devinfo; 158176667Sjfv 159176667Sjfv csa_active(csa, 1); 160176667Sjfv csa_writecodec(&csa->res, regno + BA0_AC97_RESET, data); 161176667Sjfv csa_active(csa, -1); 162176667Sjfv 163176667Sjfv return 0; 164176667Sjfv} 165176667Sjfv 166176667Sjfvstatic kobj_method_t csa_ac97_methods[] = { 167176667Sjfv KOBJMETHOD(ac97_read, csa_rdcd), 168176667Sjfv KOBJMETHOD(ac97_write, csa_wrcd), 169176667Sjfv KOBJMETHOD_END 170176667Sjfv}; 171176667SjfvAC97_DECLARE(csa_ac97); 172176667Sjfv 173176667Sjfvstatic void 174194865Sjfvcsa_setplaysamplerate(csa_res *resp, u_long ulInRate) 175194865Sjfv{ 176194865Sjfv u_long ulTemp1, ulTemp2; 177194865Sjfv u_long ulPhiIncr; 178194865Sjfv u_long ulCorrectionPerGOF, ulCorrectionPerSec; 179223198Sjhb u_long ulOutRate; 180223198Sjhb 181223198Sjhb ulOutRate = 48000; 182223198Sjhb 183194865Sjfv /* 184176667Sjfv * Compute the values used to drive the actual sample rate conversion. 185176667Sjfv * The following formulas are being computed, using inline assembly 186176667Sjfv * since we need to use 64 bit arithmetic to compute the values: 187176667Sjfv * 188176667Sjfv * ulPhiIncr = floor((Fs,in * 2^26) / Fs,out) 189176667Sjfv * ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) / 190176667Sjfv * GOF_PER_SEC) 191176667Sjfv * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - 192176667Sjfv * GOF_PER_SEC * ulCorrectionPerGOF 193176667Sjfv * 194176667Sjfv * i.e. 195176667Sjfv * 196176667Sjfv * ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) 197200243Sjfv * ulCorrectionPerGOF:ulCorrectionPerSec = 198211907Syongari * dividend:remainder(ulOther / GOF_PER_SEC) 199176667Sjfv */ 200176667Sjfv ulTemp1 = ulInRate << 16; 201176667Sjfv ulPhiIncr = ulTemp1 / ulOutRate; 202176667Sjfv ulTemp1 -= ulPhiIncr * ulOutRate; 203176667Sjfv ulTemp1 <<= 10; 204176667Sjfv ulPhiIncr <<= 10; 205176667Sjfv ulTemp2 = ulTemp1 / ulOutRate; 206176667Sjfv ulPhiIncr += ulTemp2; 207176667Sjfv ulTemp1 -= ulTemp2 * ulOutRate; 208176667Sjfv ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC; 209176667Sjfv ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC; 210176667Sjfv ulCorrectionPerSec = ulTemp1; 211176667Sjfv 212176667Sjfv /* 213176667Sjfv * Fill in the SampleRateConverter control block. 214176667Sjfv */ 215203049Sjfv csa_writemem(resp, BA1_PSRC, ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF)); 216176667Sjfv csa_writemem(resp, BA1_PPI, ulPhiIncr); 217176667Sjfv} 218176667Sjfv 219176667Sjfvstatic void 220176667Sjfvcsa_setcapturesamplerate(csa_res *resp, u_long ulOutRate) 221203049Sjfv{ 222205869Sjfv u_long ulPhiIncr, ulCoeffIncr, ulTemp1, ulTemp2; 223203049Sjfv u_long ulCorrectionPerGOF, ulCorrectionPerSec, ulInitialDelay; 224203049Sjfv u_long dwFrameGroupLength, dwCnt; 225203049Sjfv u_long ulInRate; 226209238Sjfv 227203049Sjfv ulInRate = 48000; 228177867Sjfv 229176667Sjfv /* 230176667Sjfv * We can only decimate by up to a factor of 1/9th the hardware rate. 231176667Sjfv * Return an error if an attempt is made to stray outside that limit. 232176667Sjfv */ 233176667Sjfv if((ulOutRate * 9) < ulInRate) 234205869Sjfv return; 235194865Sjfv 236181027Sjfv /* 237181027Sjfv * We can not capture at at rate greater than the Input Rate (48000). 238194865Sjfv * Return an error if an attempt is made to stray outside that limit. 239194865Sjfv */ 240176667Sjfv if(ulOutRate > ulInRate) 241176667Sjfv return; 242176667Sjfv 243176667Sjfv /* 244209241Sgnn * Compute the values used to drive the actual sample rate conversion. 245176667Sjfv * The following formulas are being computed, using inline assembly 246176667Sjfv * since we need to use 64 bit arithmetic to compute the values: 247209611Sjfv * 248209611Sjfv * ulCoeffIncr = -floor((Fs,out * 2^23) / Fs,in) 249209611Sjfv * ulPhiIncr = floor((Fs,in * 2^26) / Fs,out) 250209611Sjfv * ulCorrectionPerGOF = floor((Fs,in * 2^26 - Fs,out * ulPhiIncr) / 251209611Sjfv * GOF_PER_SEC) 252176667Sjfv * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - 253176667Sjfv * GOF_PER_SEC * ulCorrectionPerGOF 254176667Sjfv * ulInitialDelay = ceil((24 * Fs,in) / Fs,out) 255176667Sjfv * 256176667Sjfv * i.e. 257176667Sjfv * 258206001Smarius * ulCoeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) 259176667Sjfv * ulPhiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) 260176667Sjfv * ulCorrectionPerGOF:ulCorrectionPerSec = 261219753Sjfv * dividend:remainder(ulOther / GOF_PER_SEC) 262219753Sjfv * ulInitialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) 263203049Sjfv */ 264203090Sjfv ulTemp1 = ulOutRate << 16; 265176667Sjfv ulCoeffIncr = ulTemp1 / ulInRate; 266219753Sjfv ulTemp1 -= ulCoeffIncr * ulInRate; 267219753Sjfv ulTemp1 <<= 7; 268220375Sjfv ulCoeffIncr <<= 7; 269223350Sjfv ulCoeffIncr += ulTemp1 / ulInRate; 270176667Sjfv ulCoeffIncr ^= 0xFFFFFFFF; 271203354Sjfv ulCoeffIncr++; 272203354Sjfv ulTemp1 = ulInRate << 16; 273203354Sjfv ulPhiIncr = ulTemp1 / ulOutRate; 274203354Sjfv ulTemp1 -= ulPhiIncr * ulOutRate; 275176667Sjfv ulTemp1 <<= 10; 276176667Sjfv ulPhiIncr <<= 10; 277176667Sjfv ulTemp2 = ulTemp1 / ulOutRate; 278176667Sjfv ulPhiIncr += ulTemp2; 279176667Sjfv ulTemp1 -= ulTemp2 * ulOutRate; 280176667Sjfv ulCorrectionPerGOF = ulTemp1 / GOF_PER_SEC; 281176667Sjfv ulTemp1 -= ulCorrectionPerGOF * GOF_PER_SEC; 282176667Sjfv ulCorrectionPerSec = ulTemp1; 283176667Sjfv ulInitialDelay = ((ulInRate * 24) + ulOutRate - 1) / ulOutRate; 284176667Sjfv 285176667Sjfv /* 286176667Sjfv * Fill in the VariDecimate control block. 287176667Sjfv */ 288176667Sjfv csa_writemem(resp, BA1_CSRC, 289176667Sjfv ((ulCorrectionPerSec << 16) & 0xFFFF0000) | (ulCorrectionPerGOF & 0xFFFF)); 290176667Sjfv csa_writemem(resp, BA1_CCI, ulCoeffIncr); 291176667Sjfv csa_writemem(resp, BA1_CD, 292176667Sjfv (((BA1_VARIDEC_BUF_1 + (ulInitialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); 293176667Sjfv csa_writemem(resp, BA1_CPI, ulPhiIncr); 294176667Sjfv 295176667Sjfv /* 296176667Sjfv * Figure out the frame group length for the write back task. Basically, 297176667Sjfv * this is just the factors of 24000 (2^6*3*5^3) that are not present in 298176667Sjfv * the output sample rate. 299176667Sjfv */ 300176667Sjfv dwFrameGroupLength = 1; 301176667Sjfv for(dwCnt = 2; dwCnt <= 64; dwCnt *= 2) 302176667Sjfv { 303223676Sjhb if(((ulOutRate / dwCnt) * dwCnt) != 304223676Sjhb ulOutRate) 305182416Sjfv { 306176667Sjfv dwFrameGroupLength *= 2; 307176667Sjfv } 308176667Sjfv } 309176667Sjfv if(((ulOutRate / 3) * 3) != 310223676Sjhb ulOutRate) 311223676Sjhb { 312223676Sjhb dwFrameGroupLength *= 3; 313223676Sjhb } 314176667Sjfv for(dwCnt = 5; dwCnt <= 125; dwCnt *= 5) 315178523Sjfv { 316203049Sjfv if(((ulOutRate / dwCnt) * dwCnt) != 317203049Sjfv ulOutRate) 318203049Sjfv { 319203049Sjfv dwFrameGroupLength *= 5; 320182416Sjfv } 321182416Sjfv } 322182416Sjfv 323223676Sjhb /* 324223676Sjhb * Fill in the WriteBack control block. 325203049Sjfv */ 326182416Sjfv csa_writemem(resp, BA1_CFG1, dwFrameGroupLength); 327200243Sjfv csa_writemem(resp, BA1_CFG2, (0x00800000 | dwFrameGroupLength)); 328200243Sjfv csa_writemem(resp, BA1_CCST, 0x0000FFFF); 329200243Sjfv csa_writemem(resp, BA1_CSPB, ((65536 * ulOutRate) / 24000)); 330200243Sjfv csa_writemem(resp, (BA1_CSPB + 4), 0x0000FFFF); 331200243Sjfv} 332223676Sjhb 333223676Sjhbstatic void 334200243Sjfvcsa_startplaydma(struct csa_info *csa) 335200243Sjfv{ 336215781Sjfv csa_res *resp; 337215781Sjfv u_long ul; 338215781Sjfv 339215781Sjfv if (!csa->pch.dma) { 340223676Sjhb resp = &csa->res; 341223676Sjhb ul = csa_readmem(resp, BA1_PCTL); 342215781Sjfv ul &= 0x0000ffff; 343215781Sjfv csa_writemem(resp, BA1_PCTL, ul | csa->pctl); 344215781Sjfv csa_writemem(resp, BA1_PVOL, 0x80008000); 345215781Sjfv csa->pch.dma = 1; 346215781Sjfv } 347215781Sjfv} 348215781Sjfv 349215781Sjfvstatic void 350215781Sjfvcsa_startcapturedma(struct csa_info *csa) 351203049Sjfv{ 352200243Sjfv csa_res *resp; 353223676Sjhb u_long ul; 354223676Sjhb 355200243Sjfv if (!csa->rch.dma) { 356200243Sjfv resp = &csa->res; 357203049Sjfv ul = csa_readmem(resp, BA1_CCTL); 358203049Sjfv ul &= 0xffff0000; 359178523Sjfv csa_writemem(resp, BA1_CCTL, ul | csa->cctl); 360200243Sjfv csa_writemem(resp, BA1_CVOL, 0x80008000); 361194865Sjfv csa->rch.dma = 1; 362223676Sjhb } 363223676Sjhb} 364176667Sjfv 365223482Sjfvstatic void 366223482Sjfvcsa_stopplaydma(struct csa_info *csa) 367223482Sjfv{ 368223676Sjhb csa_res *resp; 369223676Sjhb u_long ul; 370223676Sjhb 371223482Sjfv if (csa->pch.dma) { 372176667Sjfv resp = &csa->res; 373176667Sjfv ul = csa_readmem(resp, BA1_PCTL); 374176667Sjfv csa->pctl = ul & 0xffff0000; 375176667Sjfv csa_writemem(resp, BA1_PCTL, ul & 0x0000ffff); 376176667Sjfv csa_writemem(resp, BA1_PVOL, 0xffffffff); 377176667Sjfv csa->pch.dma = 0; 378176667Sjfv 379176667Sjfv /* 380176667Sjfv * The bitwise pointer of the serial FIFO in the DSP 381176667Sjfv * seems to make an error upon starting or stopping the 382176667Sjfv * DSP. Clear the FIFO and correct the pointer if we 383176667Sjfv * are not capturing. 384176667Sjfv */ 385176667Sjfv if (!csa->rch.dma) { 386176667Sjfv csa_clearserialfifos(resp); 387176667Sjfv csa_writeio(resp, BA0_SERBSP, 0); 388176667Sjfv } 389176667Sjfv } 390176667Sjfv} 391176667Sjfv 392176667Sjfvstatic void 393176667Sjfvcsa_stopcapturedma(struct csa_info *csa) 394176667Sjfv{ 395176667Sjfv csa_res *resp; 396176667Sjfv u_long ul; 397176667Sjfv 398176667Sjfv if (csa->rch.dma) { 399176667Sjfv resp = &csa->res; 400176667Sjfv ul = csa_readmem(resp, BA1_CCTL); 401176667Sjfv csa->cctl = ul & 0x0000ffff; 402176667Sjfv csa_writemem(resp, BA1_CCTL, ul & 0xffff0000); 403176667Sjfv csa_writemem(resp, BA1_CVOL, 0xffffffff); 404176667Sjfv csa->rch.dma = 0; 405176667Sjfv 406176667Sjfv /* 407176667Sjfv * The bitwise pointer of the serial FIFO in the DSP 408176667Sjfv * seems to make an error upon starting or stopping the 409176667Sjfv * DSP. Clear the FIFO and correct the pointer if we 410176667Sjfv * are not playing. 411176667Sjfv */ 412176667Sjfv if (!csa->pch.dma) { 413176667Sjfv csa_clearserialfifos(resp); 414176667Sjfv csa_writeio(resp, BA0_SERBSP, 0); 415176667Sjfv } 416176667Sjfv } 417176667Sjfv} 418176667Sjfv 419176667Sjfvstatic int 420176667Sjfvcsa_startdsp(csa_res *resp) 421176667Sjfv{ 422176667Sjfv int i; 423176667Sjfv u_long ul; 424176667Sjfv 425176667Sjfv /* 426176667Sjfv * Set the frame timer to reflect the number of cycles per frame. 427176667Sjfv */ 428176667Sjfv csa_writemem(resp, BA1_FRMT, 0xadf); 429176667Sjfv 430176667Sjfv /* 431176667Sjfv * Turn on the run, run at frame, and DMA enable bits in the local copy of 432176667Sjfv * the SP control register. 433176667Sjfv */ 434176667Sjfv csa_writemem(resp, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN); 435176667Sjfv 436176667Sjfv /* 437176667Sjfv * Wait until the run at frame bit resets itself in the SP control 438176667Sjfv * register. 439176667Sjfv */ 440176667Sjfv ul = 0; 441176667Sjfv for (i = 0 ; i < 25 ; i++) { 442223350Sjfv /* 443223350Sjfv * Wait a little bit, so we don't issue PCI reads too frequently. 444223350Sjfv */ 445223350Sjfv DELAY(50); 446223350Sjfv /* 447176667Sjfv * Fetch the current value of the SP status register. 448176667Sjfv */ 449176667Sjfv ul = csa_readmem(resp, BA1_SPCR); 450176667Sjfv 451176667Sjfv /* 452176667Sjfv * If the run at frame bit has reset, then stop waiting. 453176667Sjfv */ 454209241Sgnn if((ul & SPCR_RUNFR) == 0) 455209241Sgnn break; 456176667Sjfv } 457223676Sjhb /* 458223676Sjhb * If the run at frame bit never reset, then return an error. 459223676Sjhb */ 460182416Sjfv if((ul & SPCR_RUNFR) != 0) 461220375Sjfv return (EAGAIN); 462220375Sjfv 463223350Sjfv return (0); 464220375Sjfv} 465220375Sjfv 466176667Sjfvstatic int 467176667Sjfvcsa_stopdsp(csa_res *resp) 468176667Sjfv{ 469176667Sjfv /* 470176667Sjfv * Turn off the run, run at frame, and DMA enable bits in 471176667Sjfv * the local copy of the SP control register. 472176667Sjfv */ 473176667Sjfv csa_writemem(resp, BA1_SPCR, 0); 474176667Sjfv 475176667Sjfv return (0); 476176667Sjfv} 477176667Sjfv 478176667Sjfvstatic int 479176667Sjfvcsa_setupchan(struct csa_chinfo *ch) 480176667Sjfv{ 481176667Sjfv struct csa_info *csa = ch->parent; 482176667Sjfv csa_res *resp = &csa->res; 483176667Sjfv u_long pdtc, tmp; 484176667Sjfv 485176667Sjfv if (ch->dir == PCMDIR_PLAY) { 486176667Sjfv /* direction */ 487219753Sjfv csa_writemem(resp, BA1_PBA, sndbuf_getbufaddr(ch->buffer)); 488219753Sjfv 489223350Sjfv /* format */ 490223482Sjfv csa->pfie = csa_readmem(resp, BA1_PFIE) & ~0x0000f03f; 491176667Sjfv if (!(ch->fmt & AFMT_SIGNED)) 492176667Sjfv csa->pfie |= 0x8000; 493176667Sjfv if (ch->fmt & AFMT_BIGENDIAN) 494176667Sjfv csa->pfie |= 0x4000; 495176667Sjfv if (AFMT_CHANNEL(ch->fmt) < 2) 496176667Sjfv csa->pfie |= 0x2000; 497176667Sjfv if (ch->fmt & AFMT_8BIT) 498176667Sjfv csa->pfie |= 0x1000; 499176667Sjfv csa_writemem(resp, BA1_PFIE, csa->pfie); 500176667Sjfv 501176667Sjfv tmp = 4; 502176667Sjfv if (ch->fmt & AFMT_16BIT) 503176667Sjfv tmp <<= 1; 504176667Sjfv if (AFMT_CHANNEL(ch->fmt) > 1) 505176667Sjfv tmp <<= 1; 506176667Sjfv tmp--; 507176667Sjfv 508176667Sjfv pdtc = csa_readmem(resp, BA1_PDTC) & ~0x000001ff; 509176667Sjfv pdtc |= tmp; 510176667Sjfv csa_writemem(resp, BA1_PDTC, pdtc); 511176667Sjfv 512176667Sjfv /* rate */ 513176667Sjfv csa_setplaysamplerate(resp, ch->spd); 514176667Sjfv } else if (ch->dir == PCMDIR_REC) { 515176667Sjfv /* direction */ 516176667Sjfv csa_writemem(resp, BA1_CBA, sndbuf_getbufaddr(ch->buffer)); 517176667Sjfv 518176667Sjfv /* format */ 519176667Sjfv csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 520176667Sjfv 521176667Sjfv /* rate */ 522176667Sjfv csa_setcapturesamplerate(resp, ch->spd); 523176667Sjfv } 524176667Sjfv return 0; 525176667Sjfv} 526176667Sjfv 527176667Sjfv/* -------------------------------------------------------------------- */ 528176667Sjfv/* channel interface */ 529176667Sjfv 530176667Sjfvstatic void * 531176667Sjfvcsachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 532176667Sjfv{ 533176667Sjfv struct csa_info *csa = devinfo; 534176667Sjfv struct csa_chinfo *ch = (dir == PCMDIR_PLAY)? &csa->pch : &csa->rch; 535182416Sjfv 536176667Sjfv ch->parent = csa; 537176667Sjfv ch->channel = c; 538209611Sjfv ch->buffer = b; 539218530Sjfv ch->dir = dir; 540209611Sjfv if (sndbuf_alloc(ch->buffer, csa->parent_dmat, 0, CS461x_BUFFSIZE) != 0) 541209611Sjfv return NULL; 542209611Sjfv return ch; 543209611Sjfv} 544209611Sjfv 545209611Sjfvstatic int 546209611Sjfvcsachan_setformat(kobj_t obj, void *data, u_int32_t format) 547209611Sjfv{ 548211906Syongari struct csa_chinfo *ch = data; 549211906Syongari 550211906Syongari ch->fmt = format; 551211906Syongari return 0; 552211906Syongari} 553209611Sjfv 554211913Syongaristatic u_int32_t 555211913Syongaricsachan_setspeed(kobj_t obj, void *data, u_int32_t speed) 556211913Syongari{ 557211913Syongari struct csa_chinfo *ch = data; 558211913Syongari 559211913Syongari ch->spd = speed; 560211913Syongari return ch->spd; /* XXX calc real speed */ 561211913Syongari} 562211913Syongari 563219753Sjfvstatic u_int32_t 564219753Sjfvcsachan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 565223350Sjfv{ 566223350Sjfv return CS461x_BUFFSIZE / 2; 567223350Sjfv} 568223350Sjfv 569220375Sjfvstatic int 570219753Sjfvcsachan_trigger(kobj_t obj, void *data, int go) 571219753Sjfv{ 572223350Sjfv struct csa_chinfo *ch = data; 573219753Sjfv struct csa_info *csa = ch->parent; 574219753Sjfv 575219753Sjfv if (!PCMTRIG_COMMON(go)) 576190872Sjfv return 0; 577190872Sjfv 578190872Sjfv if (go == PCMTRIG_START) { 579190872Sjfv csa_active(csa, 1); 580190872Sjfv csa_setupchan(ch); 581190872Sjfv if (ch->dir == PCMDIR_PLAY) 582190872Sjfv csa_startplaydma(csa); 583176667Sjfv else 584176667Sjfv csa_startcapturedma(csa); 585176667Sjfv } else { 586176667Sjfv if (ch->dir == PCMDIR_PLAY) 587176667Sjfv csa_stopplaydma(csa); 588176667Sjfv else 589176667Sjfv csa_stopcapturedma(csa); 590176667Sjfv csa_active(csa, -1); 591176667Sjfv } 592176667Sjfv return 0; 593176667Sjfv} 594176667Sjfv 595176667Sjfvstatic u_int32_t 596176667Sjfvcsachan_getptr(kobj_t obj, void *data) 597176667Sjfv{ 598190872Sjfv struct csa_chinfo *ch = data; 599190872Sjfv struct csa_info *csa = ch->parent; 600190872Sjfv csa_res *resp; 601176667Sjfv u_int32_t ptr; 602176667Sjfv 603176667Sjfv resp = &csa->res; 604176667Sjfv 605176667Sjfv if (ch->dir == PCMDIR_PLAY) { 606176667Sjfv ptr = csa_readmem(resp, BA1_PBA) - sndbuf_getbufaddr(ch->buffer); 607190872Sjfv if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0) 608176667Sjfv ptr >>= 1; 609176667Sjfv } else { 610176667Sjfv ptr = csa_readmem(resp, BA1_CBA) - sndbuf_getbufaddr(ch->buffer); 611176667Sjfv if ((ch->fmt & AFMT_U8) != 0 || (ch->fmt & AFMT_S8) != 0) 612176667Sjfv ptr >>= 1; 613176667Sjfv } 614176667Sjfv 615176667Sjfv return (ptr); 616176667Sjfv} 617200243Sjfv 618176667Sjfvstatic struct pcmchan_caps * 619176667Sjfvcsachan_getcaps(kobj_t obj, void *data) 620176667Sjfv{ 621176667Sjfv struct csa_chinfo *ch = data; 622176667Sjfv return (ch->dir == PCMDIR_PLAY)? &csa_playcaps : &csa_reccaps; 623176667Sjfv} 624176667Sjfv 625211907Syongaristatic kobj_method_t csachan_methods[] = { 626211907Syongari KOBJMETHOD(channel_init, csachan_init), 627176667Sjfv KOBJMETHOD(channel_setformat, csachan_setformat), 628200243Sjfv KOBJMETHOD(channel_setspeed, csachan_setspeed), 629200243Sjfv KOBJMETHOD(channel_setblocksize, csachan_setblocksize), 630200243Sjfv KOBJMETHOD(channel_trigger, csachan_trigger), 631176667Sjfv KOBJMETHOD(channel_getptr, csachan_getptr), 632176667Sjfv KOBJMETHOD(channel_getcaps, csachan_getcaps), 633176667Sjfv KOBJMETHOD_END 634176667Sjfv}; 635176667SjfvCHANNEL_DECLARE(csachan); 636176667Sjfv 637176667Sjfv/* -------------------------------------------------------------------- */ 638176667Sjfv/* The interrupt handler */ 639176667Sjfvstatic void 640176667Sjfvcsa_intr(void *p) 641176667Sjfv{ 642176667Sjfv struct csa_info *csa = p; 643176667Sjfv 644176667Sjfv if ((csa->binfo->hisr & HISR_VC0) != 0) 645176667Sjfv chn_intr(csa->pch.channel); 646176667Sjfv if ((csa->binfo->hisr & HISR_VC1) != 0) 647176667Sjfv chn_intr(csa->rch.channel); 648176667Sjfv} 649176667Sjfv 650176667Sjfv/* -------------------------------------------------------------------- */ 651176667Sjfv 652176667Sjfv/* 653181027Sjfv * Probe and attach the card 654181027Sjfv */ 655195857Sjfv 656181027Sjfvstatic int 657195857Sjfvcsa_init(struct csa_info *csa) 658181027Sjfv{ 659209241Sgnn csa_res *resp; 660209241Sgnn 661176667Sjfv resp = &csa->res; 662176667Sjfv 663176667Sjfv csa->pfie = 0; 664206001Smarius csa_stopplaydma(csa); 665206001Smarius csa_stopcapturedma(csa); 666206001Smarius 667176667Sjfv if (csa_startdsp(resp)) 668176667Sjfv return (1); 669176667Sjfv 670176667Sjfv /* Crank up the power on the DAC and ADC. */ 671176667Sjfv csa_setplaysamplerate(resp, 8000); 672223350Sjfv csa_setcapturesamplerate(resp, 8000); 673176667Sjfv /* Set defaults */ 674176667Sjfv csa_writeio(resp, BA0_EGPIODR, EGPIODR_GPOE0); 675176667Sjfv csa_writeio(resp, BA0_EGPIOPTR, EGPIOPTR_GPPT0); 676211907Syongari /* Power up amplifier */ 677211907Syongari csa_writeio(resp, BA0_EGPIODR, csa_readio(resp, BA0_EGPIODR) | 678176667Sjfv EGPIODR_GPOE2); 679176667Sjfv csa_writeio(resp, BA0_EGPIOPTR, csa_readio(resp, BA0_EGPIOPTR) | 680211913Syongari EGPIOPTR_GPPT2); 681176667Sjfv 682176667Sjfv return 0; 683176667Sjfv} 684176667Sjfv 685176667Sjfv/* Allocates resources. */ 686176667Sjfvstatic int 687176667Sjfvcsa_allocres(struct csa_info *csa, device_t dev) 688176667Sjfv{ 689176667Sjfv csa_res *resp; 690176667Sjfv 691176667Sjfv resp = &csa->res; 692176667Sjfv if (resp->io == NULL) { 693176667Sjfv resp->io = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 694176667Sjfv &resp->io_rid, RF_ACTIVE); 695176667Sjfv if (resp->io == NULL) 696176667Sjfv return (1); 697176667Sjfv } 698176667Sjfv if (resp->mem == NULL) { 699176667Sjfv resp->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 700176667Sjfv &resp->mem_rid, RF_ACTIVE); 701176667Sjfv if (resp->mem == NULL) 702176667Sjfv return (1); 703176667Sjfv } 704176667Sjfv if (resp->irq == NULL) { 705176667Sjfv resp->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 706176667Sjfv &resp->irq_rid, RF_ACTIVE | RF_SHAREABLE); 707176667Sjfv if (resp->irq == NULL) 708176667Sjfv return (1); 709176667Sjfv } 710223198Sjhb if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), 711223198Sjhb /*alignment*/CS461x_BUFFSIZE, 712206001Smarius /*boundary*/CS461x_BUFFSIZE, 713206001Smarius /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 714206001Smarius /*highaddr*/BUS_SPACE_MAXADDR, 715203354Sjfv /*filter*/NULL, /*filterarg*/NULL, 716203354Sjfv /*maxsize*/CS461x_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 717203354Sjfv /*flags*/0, /*lockfunc*/busdma_lock_mutex, 718203354Sjfv /*lockarg*/&Giant, &csa->parent_dmat) != 0) 719203354Sjfv return (1); 720176667Sjfv 721176667Sjfv return (0); 722176667Sjfv} 723176667Sjfv 724176667Sjfv/* Releases resources. */ 725176667Sjfvstatic void 726176667Sjfvcsa_releaseres(struct csa_info *csa, device_t dev) 727176667Sjfv{ 728176667Sjfv csa_res *resp; 729176667Sjfv 730176667Sjfv KASSERT(csa != NULL, ("called with bogus resource structure")); 731176667Sjfv 732176667Sjfv resp = &csa->res; 733176667Sjfv if (resp->irq != NULL) { 734176667Sjfv if (csa->ih) 735176667Sjfv bus_teardown_intr(dev, resp->irq, csa->ih); 736176667Sjfv bus_release_resource(dev, SYS_RES_IRQ, resp->irq_rid, resp->irq); 737181027Sjfv resp->irq = NULL; 738181027Sjfv } 739181027Sjfv if (resp->io != NULL) { 740181027Sjfv bus_release_resource(dev, SYS_RES_MEMORY, resp->io_rid, resp->io); 741181027Sjfv resp->io = NULL; 742181027Sjfv } 743176667Sjfv if (resp->mem != NULL) { 744176667Sjfv bus_release_resource(dev, SYS_RES_MEMORY, resp->mem_rid, resp->mem); 745176667Sjfv resp->mem = NULL; 746176667Sjfv } 747176667Sjfv if (csa->parent_dmat != NULL) { 748176667Sjfv bus_dma_tag_destroy(csa->parent_dmat); 749176667Sjfv csa->parent_dmat = NULL; 750176667Sjfv } 751223350Sjfv 752223350Sjfv free(csa, M_DEVBUF); 753176667Sjfv} 754176667Sjfv 755176667Sjfvstatic int 756176667Sjfvpcmcsa_probe(device_t dev) 757176667Sjfv{ 758176667Sjfv char *s; 759176667Sjfv struct sndcard_func *func; 760176667Sjfv 761176667Sjfv /* The parent device has already been probed. */ 762176667Sjfv 763176667Sjfv func = device_get_ivars(dev); 764176667Sjfv if (func == NULL || func->func != SCF_PCM) 765176667Sjfv return (ENXIO); 766176667Sjfv 767176667Sjfv s = "CS461x PCM Audio"; 768176667Sjfv 769176667Sjfv device_set_desc(dev, s); 770176667Sjfv return (0); 771176667Sjfv} 772176667Sjfv 773176667Sjfvstatic int 774176667Sjfvpcmcsa_attach(device_t dev) 775176667Sjfv{ 776176667Sjfv struct csa_info *csa; 777176667Sjfv csa_res *resp; 778176667Sjfv int unit; 779176667Sjfv char status[SND_STATUSLEN]; 780176667Sjfv struct ac97_info *codec; 781176667Sjfv struct sndcard_func *func; 782176667Sjfv 783176667Sjfv csa = malloc(sizeof(*csa), M_DEVBUF, M_WAITOK | M_ZERO); 784176667Sjfv unit = device_get_unit(dev); 785176667Sjfv func = device_get_ivars(dev); 786176667Sjfv csa->binfo = func->varinfo; 787176667Sjfv /* 788176667Sjfv * Fake the status of DMA so that the initial value of 789176667Sjfv * PCTL and CCTL can be stored into csa->pctl and csa->cctl, 790176667Sjfv * respectively. 791176667Sjfv */ 792176667Sjfv csa->pch.dma = csa->rch.dma = 1; 793176667Sjfv csa->active = 0; 794176667Sjfv csa->card = csa->binfo->card; 795176667Sjfv 796176667Sjfv /* Allocate the resources. */ 797176667Sjfv resp = &csa->res; 798176667Sjfv resp->io_rid = PCIR_BAR(0); 799176667Sjfv resp->mem_rid = PCIR_BAR(1); 800176667Sjfv resp->irq_rid = 0; 801176667Sjfv if (csa_allocres(csa, dev)) { 802223198Sjhb csa_releaseres(csa, dev); 803223198Sjhb return (ENXIO); 804223198Sjhb } 805176667Sjfv 806176667Sjfv csa_active(csa, 1); 807176667Sjfv if (csa_init(csa)) { 808176667Sjfv csa_releaseres(csa, dev); 809176667Sjfv return (ENXIO); 810176667Sjfv } 811223198Sjhb codec = AC97_CREATE(dev, csa, csa_ac97); 812223198Sjhb if (codec == NULL) { 813176667Sjfv csa_releaseres(csa, dev); 814223198Sjhb return (ENXIO); 815223198Sjhb } 816223198Sjhb if (csa->card->inv_eapd) 817223198Sjhb ac97_setflags(codec, AC97_F_EAPD_INV); 818223198Sjhb if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) { 819223198Sjhb ac97_destroy(codec); 820223198Sjhb csa_releaseres(csa, dev); 821223198Sjhb return (ENXIO); 822223198Sjhb } 823176667Sjfv 824176667Sjfv snprintf(status, SND_STATUSLEN, "at irq %ld %s", 825176667Sjfv rman_get_start(resp->irq),PCM_KLDSTRING(snd_csa)); 826176667Sjfv 827176667Sjfv /* Enable interrupt. */ 828176667Sjfv if (snd_setup_intr(dev, resp->irq, 0, csa_intr, csa, &csa->ih)) { 829176667Sjfv ac97_destroy(codec); 830223198Sjhb csa_releaseres(csa, dev); 831176667Sjfv return (ENXIO); 832176667Sjfv } 833176667Sjfv csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f); 834176667Sjfv csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 835176667Sjfv csa_active(csa, -1); 836176667Sjfv 837176667Sjfv if (pcm_register(dev, csa, 1, 1)) { 838176667Sjfv ac97_destroy(codec); 839176667Sjfv csa_releaseres(csa, dev); 840176667Sjfv return (ENXIO); 841176667Sjfv } 842176667Sjfv pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa); 843176667Sjfv pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa); 844176667Sjfv pcm_setstatus(dev, status); 845176667Sjfv 846176667Sjfv return (0); 847176667Sjfv} 848176667Sjfv 849176667Sjfvstatic int 850176667Sjfvpcmcsa_detach(device_t dev) 851176667Sjfv{ 852176667Sjfv int r; 853176667Sjfv struct csa_info *csa; 854176667Sjfv 855220375Sjfv r = pcm_unregister(dev); 856220375Sjfv if (r) 857220375Sjfv return r; 858220375Sjfv 859176667Sjfv csa = pcm_getdevinfo(dev); 860220375Sjfv csa_releaseres(csa, dev); 861206629Sjfv 862206629Sjfv return 0; 863206629Sjfv} 864176667Sjfv 865176667Sjfvstatic void 866176667Sjfvcsa_ac97_suspend(struct csa_info *csa) 867176667Sjfv{ 868176667Sjfv int count, i; 869176667Sjfv uint32_t tmp; 870176667Sjfv 871176667Sjfv for (count = 0x2, i=0; 872176667Sjfv (count <= CS461x_AC97_HIGHESTREGTORESTORE) && 873176667Sjfv (i < CS461x_AC97_NUMBER_RESTORE_REGS); 874176667Sjfv count += 2, i++) 875176667Sjfv csa_readcodec(&csa->res, BA0_AC97_RESET + count, &csa->ac97[i]); 876176667Sjfv 877176667Sjfv /* mute the outputs */ 878176667Sjfv csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME, 0x8000); 879176667Sjfv csa_writecodec(&csa->res, BA0_AC97_HEADPHONE_VOLUME, 0x8000); 880176667Sjfv csa_writecodec(&csa->res, BA0_AC97_MASTER_VOLUME_MONO, 0x8000); 881176667Sjfv csa_writecodec(&csa->res, BA0_AC97_PCM_OUT_VOLUME, 0x8000); 882200243Sjfv /* save the registers that cause pops */ 883206629Sjfv csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &csa->ac97_powerdown); 884215781Sjfv csa_readcodec(&csa->res, BA0_AC97_GENERAL_PURPOSE, 885176667Sjfv &csa->ac97_general_purpose); 886176667Sjfv 887176667Sjfv /* 888194865Sjfv * And power down everything on the AC97 codec. Well, for now, 889194865Sjfv * only power down the DAC/ADC and MIXER VREFON components. 890194865Sjfv * trouble with removing VREF. 891194865Sjfv */ 892194865Sjfv 893176667Sjfv /* MIXVON */ 894176667Sjfv csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp); 895176667Sjfv csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 896176667Sjfv tmp | CS_AC97_POWER_CONTROL_MIXVON); 897194865Sjfv /* ADC */ 898176667Sjfv csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp); 899176667Sjfv csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 900176667Sjfv tmp | CS_AC97_POWER_CONTROL_ADC); 901176667Sjfv /* DAC */ 902176667Sjfv csa_readcodec(&csa->res, BA0_AC97_POWERDOWN, &tmp); 903176667Sjfv csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 904194865Sjfv tmp | CS_AC97_POWER_CONTROL_DAC); 905176667Sjfv} 906176667Sjfv 907223198Sjhbstatic void 908194865Sjfvcsa_ac97_resume(struct csa_info *csa) 909194865Sjfv{ 910194865Sjfv int count, i; 911194865Sjfv 912194865Sjfv /* 913194865Sjfv * First, we restore the state of the general purpose register. This 914194865Sjfv * contains the mic select (mic1 or mic2) and if we restore this after 915209068Sjfv * we restore the mic volume/boost state and mic2 was selected at 916209068Sjfv * suspend time, we will end up with a brief period of time where mic1 917209068Sjfv * is selected with the volume/boost settings for mic2, causing 918209068Sjfv * acoustic feedback. So we restore the general purpose register 919194865Sjfv * first, thereby getting the correct mic selected before we restore 920194865Sjfv * the mic volume/boost. 921194865Sjfv */ 922194865Sjfv csa_writecodec(&csa->res, BA0_AC97_GENERAL_PURPOSE, 923205869Sjfv csa->ac97_general_purpose); 924194865Sjfv /* 925209068Sjfv * Now, while the outputs are still muted, restore the state of power 926194865Sjfv * on the AC97 part. 927194865Sjfv */ 928194865Sjfv csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, csa->ac97_powerdown); 929194865Sjfv /* 930209068Sjfv * Restore just the first set of registers, from register number 931194865Sjfv * 0x02 to the register number that ulHighestRegToRestore specifies. 932223198Sjhb */ 933209068Sjfv for (count = 0x2, i=0; 934194865Sjfv (count <= CS461x_AC97_HIGHESTREGTORESTORE) && 935194865Sjfv (i < CS461x_AC97_NUMBER_RESTORE_REGS); 936194865Sjfv count += 2, i++) 937194865Sjfv csa_writecodec(&csa->res, BA0_AC97_RESET + count, csa->ac97[i]); 938194865Sjfv} 939194865Sjfv 940194865Sjfvstatic int 941194865Sjfvpcmcsa_suspend(device_t dev) 942194865Sjfv{ 943203049Sjfv struct csa_info *csa; 944194865Sjfv csa_res *resp; 945203049Sjfv 946203049Sjfv csa = pcm_getdevinfo(dev); 947203049Sjfv resp = &csa->res; 948203049Sjfv 949203049Sjfv csa_active(csa, 1); 950203049Sjfv 951194865Sjfv /* playback interrupt disable */ 952194865Sjfv csa_writemem(resp, BA1_PFIE, 953194865Sjfv (csa_readmem(resp, BA1_PFIE) & ~0x0000f03f) | 0x00000010); 954203049Sjfv /* capture interrupt disable */ 955203834Smlaier csa_writemem(resp, BA1_CIE, 956203049Sjfv (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000011); 957203834Smlaier csa_stopplaydma(csa); 958203834Smlaier csa_stopcapturedma(csa); 959203834Smlaier 960203834Smlaier csa_ac97_suspend(csa); 961203834Smlaier 962203049Sjfv csa_resetdsp(resp); 963206629Sjfv 964194865Sjfv csa_stopdsp(resp); 965203049Sjfv /* 966203049Sjfv * Power down the DAC and ADC. For now leave the other areas on. 967203049Sjfv */ 968203049Sjfv csa_writecodec(&csa->res, BA0_AC97_POWERDOWN, 0x300); 969203049Sjfv /* 970203049Sjfv * Power down the PLL. 971203049Sjfv */ 972203049Sjfv csa_writemem(resp, BA0_CLKCR1, 0); 973203049Sjfv /* 974194865Sjfv * Turn off the Processor by turning off the software clock 975194865Sjfv * enable flag in the clock control register. 976220375Sjfv */ 977220375Sjfv csa_writemem(resp, BA0_CLKCR1, 978220375Sjfv csa_readmem(resp, BA0_CLKCR1) & ~CLKCR1_SWCE); 979220375Sjfv 980220375Sjfv csa_active(csa, -1); 981220375Sjfv 982194865Sjfv return 0; 983203049Sjfv} 984203049Sjfv 985194865Sjfvstatic int 986215781Sjfvpcmcsa_resume(device_t dev) 987206629Sjfv{ 988194865Sjfv struct csa_info *csa; 989194865Sjfv csa_res *resp; 990194865Sjfv 991194865Sjfv csa = pcm_getdevinfo(dev); 992194865Sjfv resp = &csa->res; 993223198Sjhb 994223198Sjhb csa_active(csa, 1); 995223198Sjhb 996223198Sjhb /* cs_hardware_init */ 997223198Sjhb csa_stopplaydma(csa); 998223198Sjhb csa_stopcapturedma(csa); 999223198Sjhb csa_ac97_resume(csa); 1000223198Sjhb if (csa_startdsp(resp)) 1001223198Sjhb return (ENXIO); 1002223198Sjhb /* Enable interrupts on the part. */ 1003223198Sjhb if ((csa_readio(resp, BA0_HISR) & HISR_INTENA) == 0) 1004223198Sjhb csa_writeio(resp, BA0_HICR, HICR_IEV | HICR_CHGM); 1005223198Sjhb /* playback interrupt enable */ 1006223198Sjhb csa_writemem(resp, BA1_PFIE, csa_readmem(resp, BA1_PFIE) & ~0x0000f03f); 1007223198Sjhb /* capture interrupt enable */ 1008223198Sjhb csa_writemem(resp, BA1_CIE, 1009194865Sjfv (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001); 1010194865Sjfv /* cs_restart_part */ 1011194865Sjfv csa_setupchan(&csa->pch); 1012194865Sjfv csa_startplaydma(csa); 1013194865Sjfv csa_setupchan(&csa->rch); 1014194865Sjfv csa_startcapturedma(csa); 1015194865Sjfv 1016194865Sjfv csa_active(csa, -1); 1017194865Sjfv 1018194865Sjfv return 0; 1019194865Sjfv} 1020194865Sjfv 1021194865Sjfvstatic device_method_t pcmcsa_methods[] = { 1022194865Sjfv /* Device interface */ 1023194865Sjfv DEVMETHOD(device_probe , pcmcsa_probe ), 1024194865Sjfv DEVMETHOD(device_attach, pcmcsa_attach), 1025194865Sjfv DEVMETHOD(device_detach, pcmcsa_detach), 1026223198Sjhb DEVMETHOD(device_suspend, pcmcsa_suspend), 1027194865Sjfv DEVMETHOD(device_resume, pcmcsa_resume), 1028176667Sjfv 1029176667Sjfv { 0, 0 }, 1030176667Sjfv}; 1031176667Sjfv 1032176667Sjfvstatic driver_t pcmcsa_driver = { 1033176667Sjfv "pcm", 1034176667Sjfv pcmcsa_methods, 1035176667Sjfv PCM_SOFTC_SIZE, 1036176667Sjfv}; 1037176667Sjfv 1038176667SjfvDRIVER_MODULE(snd_csapcm, csa, pcmcsa_driver, pcm_devclass, 0, 0); 1039176667SjfvMODULE_DEPEND(snd_csapcm, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 1040176667SjfvMODULE_DEPEND(snd_csapcm, snd_csa, 1, 1, 1); 1041223350SjfvMODULE_VERSION(snd_csapcm, 1); 1042223350Sjfv