3886 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Maintained by Jaroslav Kysela <perex@perex.cz>4 * Originated by audio@tridentmicro.com5 * Fri Feb 19 15:55:28 MST 19996 * Routines for control of Trident 4DWave (DX and NX) chip7 *8 * BUGS:9 *10 * TODO:11 * ---12 *13 * SiS7018 S/PDIF support by Thomas Winischhofer <thomas@winischhofer.net>14 */15 16#include <linux/delay.h>17#include <linux/init.h>18#include <linux/interrupt.h>19#include <linux/pci.h>20#include <linux/slab.h>21#include <linux/vmalloc.h>22#include <linux/gameport.h>23#include <linux/dma-mapping.h>24#include <linux/export.h>25#include <linux/io.h>26 27#include <sound/core.h>28#include <sound/info.h>29#include <sound/control.h>30#include <sound/tlv.h>31#include "trident.h"32#include <sound/asoundef.h>33 34static int snd_trident_pcm_mixer_build(struct snd_trident *trident,35 struct snd_trident_voice * voice,36 struct snd_pcm_substream *substream);37static int snd_trident_pcm_mixer_free(struct snd_trident *trident,38 struct snd_trident_voice * voice,39 struct snd_pcm_substream *substream);40static irqreturn_t snd_trident_interrupt(int irq, void *dev_id);41static int snd_trident_sis_reset(struct snd_trident *trident);42 43static void snd_trident_clear_voices(struct snd_trident * trident,44 unsigned short v_min, unsigned short v_max);45static void snd_trident_free(struct snd_card *card);46 47/*48 * common I/O routines49 */50 51 52#if 053static void snd_trident_print_voice_regs(struct snd_trident *trident, int voice)54{55 unsigned int val, tmp;56 57 dev_dbg(trident->card->dev, "Trident voice %i:\n", voice);58 outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR));59 val = inl(TRID_REG(trident, CH_LBA));60 dev_dbg(trident->card->dev, "LBA: 0x%x\n", val);61 val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));62 dev_dbg(trident->card->dev, "GVSel: %i\n", val >> 31);63 dev_dbg(trident->card->dev, "Pan: 0x%x\n", (val >> 24) & 0x7f);64 dev_dbg(trident->card->dev, "Vol: 0x%x\n", (val >> 16) & 0xff);65 dev_dbg(trident->card->dev, "CTRL: 0x%x\n", (val >> 12) & 0x0f);66 dev_dbg(trident->card->dev, "EC: 0x%x\n", val & 0x0fff);67 if (trident->device != TRIDENT_DEVICE_ID_NX) {68 val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS));69 dev_dbg(trident->card->dev, "CSO: 0x%x\n", val >> 16);70 dev_dbg(trident->card->dev, "Alpha: 0x%x\n", (val >> 4) & 0x0fff);71 dev_dbg(trident->card->dev, "FMS: 0x%x\n", val & 0x0f);72 val = inl(TRID_REG(trident, CH_DX_ESO_DELTA));73 dev_dbg(trident->card->dev, "ESO: 0x%x\n", val >> 16);74 dev_dbg(trident->card->dev, "Delta: 0x%x\n", val & 0xffff);75 val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL));76 } else { // TRIDENT_DEVICE_ID_NX77 val = inl(TRID_REG(trident, CH_NX_DELTA_CSO));78 tmp = (val >> 24) & 0xff;79 dev_dbg(trident->card->dev, "CSO: 0x%x\n", val & 0x00ffffff);80 val = inl(TRID_REG(trident, CH_NX_DELTA_ESO));81 tmp |= (val >> 16) & 0xff00;82 dev_dbg(trident->card->dev, "Delta: 0x%x\n", tmp);83 dev_dbg(trident->card->dev, "ESO: 0x%x\n", val & 0x00ffffff);84 val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL));85 dev_dbg(trident->card->dev, "Alpha: 0x%x\n", val >> 20);86 dev_dbg(trident->card->dev, "FMS: 0x%x\n", (val >> 16) & 0x0f);87 }88 dev_dbg(trident->card->dev, "FMC: 0x%x\n", (val >> 14) & 3);89 dev_dbg(trident->card->dev, "RVol: 0x%x\n", (val >> 7) & 0x7f);90 dev_dbg(trident->card->dev, "CVol: 0x%x\n", val & 0x7f);91}92#endif93 94/*---------------------------------------------------------------------------95 unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned short reg)96 97 Description: This routine will do all of the reading from the external98 CODEC (AC97).99 100 Parameters: ac97 - ac97 codec structure101 reg - CODEC register index, from AC97 Hal.102 103 returns: 16 bit value read from the AC97.104 105 ---------------------------------------------------------------------------*/106static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned short reg)107{108 unsigned int data = 0, treg;109 unsigned short count = 0xffff;110 unsigned long flags;111 struct snd_trident *trident = ac97->private_data;112 113 spin_lock_irqsave(&trident->reg_lock, flags);114 if (trident->device == TRIDENT_DEVICE_ID_DX) {115 data = (DX_AC97_BUSY_READ | (reg & 0x000000ff));116 outl(data, TRID_REG(trident, DX_ACR1_AC97_R));117 do {118 data = inl(TRID_REG(trident, DX_ACR1_AC97_R));119 if ((data & DX_AC97_BUSY_READ) == 0)120 break;121 } while (--count);122 } else if (trident->device == TRIDENT_DEVICE_ID_NX) {123 data = (NX_AC97_BUSY_READ | (reg & 0x000000ff));124 treg = ac97->num == 0 ? NX_ACR2_AC97_R_PRIMARY : NX_ACR3_AC97_R_SECONDARY;125 outl(data, TRID_REG(trident, treg));126 do {127 data = inl(TRID_REG(trident, treg));128 if ((data & 0x00000C00) == 0)129 break;130 } while (--count);131 } else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {132 data = SI_AC97_BUSY_READ | SI_AC97_AUDIO_BUSY | (reg & 0x000000ff);133 if (ac97->num == 1)134 data |= SI_AC97_SECONDARY;135 outl(data, TRID_REG(trident, SI_AC97_READ));136 do {137 data = inl(TRID_REG(trident, SI_AC97_READ));138 if ((data & (SI_AC97_BUSY_READ)) == 0)139 break;140 } while (--count);141 }142 143 if (count == 0 && !trident->ac97_detect) {144 dev_err(trident->card->dev,145 "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n",146 reg, data);147 data = 0;148 }149 150 spin_unlock_irqrestore(&trident->reg_lock, flags);151 return ((unsigned short) (data >> 16));152}153 154/*---------------------------------------------------------------------------155 void snd_trident_codec_write(struct snd_ac97 *ac97, unsigned short reg,156 unsigned short wdata)157 158 Description: This routine will do all of the writing to the external159 CODEC (AC97).160 161 Parameters: ac97 - ac97 codec structure162 reg - CODEC register index, from AC97 Hal.163 data - Lower 16 bits are the data to write to CODEC.164 165 returns: TRUE if everything went ok, else FALSE.166 167 ---------------------------------------------------------------------------*/168static void snd_trident_codec_write(struct snd_ac97 *ac97, unsigned short reg,169 unsigned short wdata)170{171 unsigned int address, data;172 unsigned short count = 0xffff;173 unsigned long flags;174 struct snd_trident *trident = ac97->private_data;175 176 data = ((unsigned long) wdata) << 16;177 178 spin_lock_irqsave(&trident->reg_lock, flags);179 if (trident->device == TRIDENT_DEVICE_ID_DX) {180 address = DX_ACR0_AC97_W;181 182 /* read AC-97 write register status */183 do {184 if ((inw(TRID_REG(trident, address)) & DX_AC97_BUSY_WRITE) == 0)185 break;186 } while (--count);187 188 data |= (DX_AC97_BUSY_WRITE | (reg & 0x000000ff));189 } else if (trident->device == TRIDENT_DEVICE_ID_NX) {190 address = NX_ACR1_AC97_W;191 192 /* read AC-97 write register status */193 do {194 if ((inw(TRID_REG(trident, address)) & NX_AC97_BUSY_WRITE) == 0)195 break;196 } while (--count);197 198 data |= (NX_AC97_BUSY_WRITE | (ac97->num << 8) | (reg & 0x000000ff));199 } else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {200 address = SI_AC97_WRITE;201 202 /* read AC-97 write register status */203 do {204 if ((inw(TRID_REG(trident, address)) & (SI_AC97_BUSY_WRITE)) == 0)205 break;206 } while (--count);207 208 data |= SI_AC97_BUSY_WRITE | SI_AC97_AUDIO_BUSY | (reg & 0x000000ff);209 if (ac97->num == 1)210 data |= SI_AC97_SECONDARY;211 } else {212 address = 0; /* keep GCC happy */213 count = 0; /* return */214 }215 216 if (count == 0) {217 spin_unlock_irqrestore(&trident->reg_lock, flags);218 return;219 }220 outl(data, TRID_REG(trident, address));221 spin_unlock_irqrestore(&trident->reg_lock, flags);222}223 224/*---------------------------------------------------------------------------225 void snd_trident_enable_eso(struct snd_trident *trident)226 227 Description: This routine will enable end of loop interrupts.228 End of loop interrupts will occur when a running229 channel reaches ESO.230 Also enables middle of loop interrupts.231 232 Parameters: trident - pointer to target device class for 4DWave.233 234 ---------------------------------------------------------------------------*/235 236static void snd_trident_enable_eso(struct snd_trident * trident)237{238 unsigned int val;239 240 val = inl(TRID_REG(trident, T4D_LFO_GC_CIR));241 val |= ENDLP_IE;242 val |= MIDLP_IE;243 if (trident->device == TRIDENT_DEVICE_ID_SI7018)244 val |= BANK_B_EN;245 outl(val, TRID_REG(trident, T4D_LFO_GC_CIR));246}247 248/*---------------------------------------------------------------------------249 void snd_trident_disable_eso(struct snd_trident *trident)250 251 Description: This routine will disable end of loop interrupts.252 End of loop interrupts will occur when a running253 channel reaches ESO.254 Also disables middle of loop interrupts.255 256 Parameters: 257 trident - pointer to target device class for 4DWave.258 259 returns: TRUE if everything went ok, else FALSE.260 261 ---------------------------------------------------------------------------*/262 263static void snd_trident_disable_eso(struct snd_trident * trident)264{265 unsigned int tmp;266 267 tmp = inl(TRID_REG(trident, T4D_LFO_GC_CIR));268 tmp &= ~ENDLP_IE;269 tmp &= ~MIDLP_IE;270 outl(tmp, TRID_REG(trident, T4D_LFO_GC_CIR));271}272 273/*---------------------------------------------------------------------------274 void snd_trident_start_voice(struct snd_trident * trident, unsigned int voice)275 276 Description: Start a voice, any channel 0 thru 63.277 This routine automatically handles the fact that there are278 more than 32 channels available.279 280 Parameters : voice - Voice number 0 thru n.281 trident - pointer to target device class for 4DWave.282 283 Return Value: None.284 285 ---------------------------------------------------------------------------*/286 287void snd_trident_start_voice(struct snd_trident * trident, unsigned int voice)288{289 unsigned int mask = 1 << (voice & 0x1f);290 unsigned int reg = (voice & 0x20) ? T4D_START_B : T4D_START_A;291 292 outl(mask, TRID_REG(trident, reg));293}294 295EXPORT_SYMBOL(snd_trident_start_voice);296 297/*---------------------------------------------------------------------------298 void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice)299 300 Description: Stop a voice, any channel 0 thru 63.301 This routine automatically handles the fact that there are302 more than 32 channels available.303 304 Parameters : voice - Voice number 0 thru n.305 trident - pointer to target device class for 4DWave.306 307 Return Value: None.308 309 ---------------------------------------------------------------------------*/310 311void snd_trident_stop_voice(struct snd_trident * trident, unsigned int voice)312{313 unsigned int mask = 1 << (voice & 0x1f);314 unsigned int reg = (voice & 0x20) ? T4D_STOP_B : T4D_STOP_A;315 316 outl(mask, TRID_REG(trident, reg));317}318 319EXPORT_SYMBOL(snd_trident_stop_voice);320 321/*---------------------------------------------------------------------------322 int snd_trident_allocate_pcm_channel(struct snd_trident *trident)323 324 Description: Allocate hardware channel in Bank B (32-63).325 326 Parameters : trident - pointer to target device class for 4DWave.327 328 Return Value: hardware channel - 32-63 or -1 when no channel is available329 330 ---------------------------------------------------------------------------*/331 332static int snd_trident_allocate_pcm_channel(struct snd_trident * trident)333{334 int idx;335 336 if (trident->ChanPCMcnt >= trident->ChanPCM)337 return -1;338 for (idx = 31; idx >= 0; idx--) {339 if (!(trident->ChanMap[T4D_BANK_B] & (1 << idx))) {340 trident->ChanMap[T4D_BANK_B] |= 1 << idx;341 trident->ChanPCMcnt++;342 return idx + 32;343 }344 }345 return -1;346}347 348/*---------------------------------------------------------------------------349 void snd_trident_free_pcm_channel(int channel)350 351 Description: Free hardware channel in Bank B (32-63)352 353 Parameters : trident - pointer to target device class for 4DWave.354 channel - hardware channel number 0-63355 356 Return Value: none357 358 ---------------------------------------------------------------------------*/359 360static void snd_trident_free_pcm_channel(struct snd_trident *trident, int channel)361{362 if (channel < 32 || channel > 63)363 return;364 channel &= 0x1f;365 if (trident->ChanMap[T4D_BANK_B] & (1 << channel)) {366 trident->ChanMap[T4D_BANK_B] &= ~(1 << channel);367 trident->ChanPCMcnt--;368 }369}370 371/*---------------------------------------------------------------------------372 unsigned int snd_trident_allocate_synth_channel(void)373 374 Description: Allocate hardware channel in Bank A (0-31).375 376 Parameters : trident - pointer to target device class for 4DWave.377 378 Return Value: hardware channel - 0-31 or -1 when no channel is available379 380 ---------------------------------------------------------------------------*/381 382static int snd_trident_allocate_synth_channel(struct snd_trident * trident)383{384 int idx;385 386 for (idx = 31; idx >= 0; idx--) {387 if (!(trident->ChanMap[T4D_BANK_A] & (1 << idx))) {388 trident->ChanMap[T4D_BANK_A] |= 1 << idx;389 trident->synth.ChanSynthCount++;390 return idx;391 }392 }393 return -1;394}395 396/*---------------------------------------------------------------------------397 void snd_trident_free_synth_channel( int channel )398 399 Description: Free hardware channel in Bank B (0-31).400 401 Parameters : trident - pointer to target device class for 4DWave.402 channel - hardware channel number 0-63403 404 Return Value: none405 406 ---------------------------------------------------------------------------*/407 408static void snd_trident_free_synth_channel(struct snd_trident *trident, int channel)409{410 if (channel < 0 || channel > 31)411 return;412 channel &= 0x1f;413 if (trident->ChanMap[T4D_BANK_A] & (1 << channel)) {414 trident->ChanMap[T4D_BANK_A] &= ~(1 << channel);415 trident->synth.ChanSynthCount--;416 }417}418 419/*---------------------------------------------------------------------------420 snd_trident_write_voice_regs421 422 Description: This routine will complete and write the 5 hardware channel423 registers to hardware.424 425 Parameters: trident - pointer to target device class for 4DWave.426 voice - synthesizer voice structure427 Each register field.428 429 ---------------------------------------------------------------------------*/430 431void snd_trident_write_voice_regs(struct snd_trident * trident,432 struct snd_trident_voice * voice)433{434 unsigned int FmcRvolCvol;435 unsigned int regs[5];436 437 regs[1] = voice->LBA;438 regs[4] = (voice->GVSel << 31) |439 ((voice->Pan & 0x0000007f) << 24) |440 ((voice->CTRL & 0x0000000f) << 12);441 FmcRvolCvol = ((voice->FMC & 3) << 14) |442 ((voice->RVol & 0x7f) << 7) |443 (voice->CVol & 0x7f);444 445 switch (trident->device) {446 case TRIDENT_DEVICE_ID_SI7018:447 regs[4] |= voice->number > 31 ?448 (voice->Vol & 0x000003ff) :449 ((voice->Vol & 0x00003fc) << (16-2)) |450 (voice->EC & 0x00000fff);451 regs[0] = (voice->CSO << 16) | ((voice->Alpha & 0x00000fff) << 4) |452 (voice->FMS & 0x0000000f);453 regs[2] = (voice->ESO << 16) | (voice->Delta & 0x0ffff);454 regs[3] = (voice->Attribute << 16) | FmcRvolCvol;455 break;456 case TRIDENT_DEVICE_ID_DX:457 regs[4] |= ((voice->Vol & 0x000003fc) << (16-2)) |458 (voice->EC & 0x00000fff);459 regs[0] = (voice->CSO << 16) | ((voice->Alpha & 0x00000fff) << 4) |460 (voice->FMS & 0x0000000f);461 regs[2] = (voice->ESO << 16) | (voice->Delta & 0x0ffff);462 regs[3] = FmcRvolCvol;463 break;464 case TRIDENT_DEVICE_ID_NX:465 regs[4] |= ((voice->Vol & 0x000003fc) << (16-2)) |466 (voice->EC & 0x00000fff);467 regs[0] = (voice->Delta << 24) | (voice->CSO & 0x00ffffff);468 regs[2] = ((voice->Delta << 16) & 0xff000000) |469 (voice->ESO & 0x00ffffff);470 regs[3] = (voice->Alpha << 20) |471 ((voice->FMS & 0x0000000f) << 16) | FmcRvolCvol;472 break;473 default:474 snd_BUG();475 return;476 }477 478 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));479 outl(regs[0], TRID_REG(trident, CH_START + 0));480 outl(regs[1], TRID_REG(trident, CH_START + 4));481 outl(regs[2], TRID_REG(trident, CH_START + 8));482 outl(regs[3], TRID_REG(trident, CH_START + 12));483 outl(regs[4], TRID_REG(trident, CH_START + 16));484 485#if 0486 dev_dbg(trident->card->dev, "written %i channel:\n", voice->number);487 dev_dbg(trident->card->dev, " regs[0] = 0x%x/0x%x\n",488 regs[0], inl(TRID_REG(trident, CH_START + 0)));489 dev_dbg(trident->card->dev, " regs[1] = 0x%x/0x%x\n",490 regs[1], inl(TRID_REG(trident, CH_START + 4)));491 dev_dbg(trident->card->dev, " regs[2] = 0x%x/0x%x\n",492 regs[2], inl(TRID_REG(trident, CH_START + 8)));493 dev_dbg(trident->card->dev, " regs[3] = 0x%x/0x%x\n",494 regs[3], inl(TRID_REG(trident, CH_START + 12)));495 dev_dbg(trident->card->dev, " regs[4] = 0x%x/0x%x\n",496 regs[4], inl(TRID_REG(trident, CH_START + 16)));497#endif498}499 500EXPORT_SYMBOL(snd_trident_write_voice_regs);501 502/*---------------------------------------------------------------------------503 snd_trident_write_cso_reg504 505 Description: This routine will write the new CSO offset506 register to hardware.507 508 Parameters: trident - pointer to target device class for 4DWave.509 voice - synthesizer voice structure510 CSO - new CSO value511 512 ---------------------------------------------------------------------------*/513 514static void snd_trident_write_cso_reg(struct snd_trident * trident,515 struct snd_trident_voice * voice,516 unsigned int CSO)517{518 voice->CSO = CSO;519 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));520 if (trident->device != TRIDENT_DEVICE_ID_NX) {521 outw(voice->CSO, TRID_REG(trident, CH_DX_CSO_ALPHA_FMS) + 2);522 } else {523 outl((voice->Delta << 24) |524 (voice->CSO & 0x00ffffff), TRID_REG(trident, CH_NX_DELTA_CSO));525 }526}527 528/*---------------------------------------------------------------------------529 snd_trident_write_eso_reg530 531 Description: This routine will write the new ESO offset532 register to hardware.533 534 Parameters: trident - pointer to target device class for 4DWave.535 voice - synthesizer voice structure536 ESO - new ESO value537 538 ---------------------------------------------------------------------------*/539 540static void snd_trident_write_eso_reg(struct snd_trident * trident,541 struct snd_trident_voice * voice,542 unsigned int ESO)543{544 voice->ESO = ESO;545 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));546 if (trident->device != TRIDENT_DEVICE_ID_NX) {547 outw(voice->ESO, TRID_REG(trident, CH_DX_ESO_DELTA) + 2);548 } else {549 outl(((voice->Delta << 16) & 0xff000000) | (voice->ESO & 0x00ffffff),550 TRID_REG(trident, CH_NX_DELTA_ESO));551 }552}553 554/*---------------------------------------------------------------------------555 snd_trident_write_vol_reg556 557 Description: This routine will write the new voice volume558 register to hardware.559 560 Parameters: trident - pointer to target device class for 4DWave.561 voice - synthesizer voice structure562 Vol - new voice volume563 564 ---------------------------------------------------------------------------*/565 566static void snd_trident_write_vol_reg(struct snd_trident * trident,567 struct snd_trident_voice * voice,568 unsigned int Vol)569{570 voice->Vol = Vol;571 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));572 switch (trident->device) {573 case TRIDENT_DEVICE_ID_DX:574 case TRIDENT_DEVICE_ID_NX:575 outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2));576 break;577 case TRIDENT_DEVICE_ID_SI7018:578 /* dev_dbg(trident->card->dev, "voice->Vol = 0x%x\n", voice->Vol); */579 outw((voice->CTRL << 12) | voice->Vol,580 TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC));581 break;582 }583}584 585/*---------------------------------------------------------------------------586 snd_trident_write_pan_reg587 588 Description: This routine will write the new voice pan589 register to hardware.590 591 Parameters: trident - pointer to target device class for 4DWave.592 voice - synthesizer voice structure593 Pan - new pan value594 595 ---------------------------------------------------------------------------*/596 597static void snd_trident_write_pan_reg(struct snd_trident * trident,598 struct snd_trident_voice * voice,599 unsigned int Pan)600{601 voice->Pan = Pan;602 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));603 outb(((voice->GVSel & 0x01) << 7) | (voice->Pan & 0x7f),604 TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 3));605}606 607/*---------------------------------------------------------------------------608 snd_trident_write_rvol_reg609 610 Description: This routine will write the new reverb volume611 register to hardware.612 613 Parameters: trident - pointer to target device class for 4DWave.614 voice - synthesizer voice structure615 RVol - new reverb volume616 617 ---------------------------------------------------------------------------*/618 619static void snd_trident_write_rvol_reg(struct snd_trident * trident,620 struct snd_trident_voice * voice,621 unsigned int RVol)622{623 voice->RVol = RVol;624 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));625 outw(((voice->FMC & 0x0003) << 14) | ((voice->RVol & 0x007f) << 7) |626 (voice->CVol & 0x007f),627 TRID_REG(trident, trident->device == TRIDENT_DEVICE_ID_NX ?628 CH_NX_ALPHA_FMS_FMC_RVOL_CVOL : CH_DX_FMC_RVOL_CVOL));629}630 631/*---------------------------------------------------------------------------632 snd_trident_write_cvol_reg633 634 Description: This routine will write the new chorus volume635 register to hardware.636 637 Parameters: trident - pointer to target device class for 4DWave.638 voice - synthesizer voice structure639 CVol - new chorus volume640 641 ---------------------------------------------------------------------------*/642 643static void snd_trident_write_cvol_reg(struct snd_trident * trident,644 struct snd_trident_voice * voice,645 unsigned int CVol)646{647 voice->CVol = CVol;648 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));649 outw(((voice->FMC & 0x0003) << 14) | ((voice->RVol & 0x007f) << 7) |650 (voice->CVol & 0x007f),651 TRID_REG(trident, trident->device == TRIDENT_DEVICE_ID_NX ?652 CH_NX_ALPHA_FMS_FMC_RVOL_CVOL : CH_DX_FMC_RVOL_CVOL));653}654 655/*---------------------------------------------------------------------------656 snd_trident_convert_rate657 658 Description: This routine converts rate in HZ to hardware delta value.659 660 Parameters: trident - pointer to target device class for 4DWave.661 rate - Real or Virtual channel number.662 663 Returns: Delta value.664 665 ---------------------------------------------------------------------------*/666static unsigned int snd_trident_convert_rate(unsigned int rate)667{668 unsigned int delta;669 670 // We special case 44100 and 8000 since rounding with the equation671 // does not give us an accurate enough value. For 11025 and 22050672 // the equation gives us the best answer. All other frequencies will673 // also use the equation. JDW674 if (rate == 44100)675 delta = 0xeb3;676 else if (rate == 8000)677 delta = 0x2ab;678 else if (rate == 48000)679 delta = 0x1000;680 else681 delta = DIV_ROUND_CLOSEST(rate << 12, 48000) & 0x0000ffff;682 return delta;683}684 685/*---------------------------------------------------------------------------686 snd_trident_convert_adc_rate687 688 Description: This routine converts rate in HZ to hardware delta value.689 690 Parameters: trident - pointer to target device class for 4DWave.691 rate - Real or Virtual channel number.692 693 Returns: Delta value.694 695 ---------------------------------------------------------------------------*/696static unsigned int snd_trident_convert_adc_rate(unsigned int rate)697{698 unsigned int delta;699 700 // We special case 44100 and 8000 since rounding with the equation701 // does not give us an accurate enough value. For 11025 and 22050702 // the equation gives us the best answer. All other frequencies will703 // also use the equation. JDW704 if (rate == 44100)705 delta = 0x116a;706 else if (rate == 8000)707 delta = 0x6000;708 else if (rate == 48000)709 delta = 0x1000;710 else711 delta = ((48000 << 12) / rate) & 0x0000ffff;712 return delta;713}714 715/*---------------------------------------------------------------------------716 snd_trident_spurious_threshold717 718 Description: This routine converts rate in HZ to spurious threshold.719 720 Parameters: trident - pointer to target device class for 4DWave.721 rate - Real or Virtual channel number.722 723 Returns: Delta value.724 725 ---------------------------------------------------------------------------*/726static unsigned int snd_trident_spurious_threshold(unsigned int rate,727 unsigned int period_size)728{729 unsigned int res = (rate * period_size) / 48000;730 if (res < 64)731 res = res / 2;732 else733 res -= 32;734 return res;735}736 737/*---------------------------------------------------------------------------738 snd_trident_control_mode739 740 Description: This routine returns a control mode for a PCM channel.741 742 Parameters: trident - pointer to target device class for 4DWave.743 substream - PCM substream744 745 Returns: Control value.746 747 ---------------------------------------------------------------------------*/748static unsigned int snd_trident_control_mode(struct snd_pcm_substream *substream)749{750 unsigned int CTRL;751 struct snd_pcm_runtime *runtime = substream->runtime;752 753 /* set ctrl mode754 CTRL default: 8-bit (unsigned) mono, loop mode enabled755 */756 CTRL = 0x00000001;757 if (snd_pcm_format_width(runtime->format) == 16)758 CTRL |= 0x00000008; // 16-bit data759 if (snd_pcm_format_signed(runtime->format))760 CTRL |= 0x00000002; // signed data761 if (runtime->channels > 1)762 CTRL |= 0x00000004; // stereo data763 return CTRL;764}765 766/*767 * PCM part768 */769 770/*---------------------------------------------------------------------------771 snd_trident_allocate_pcm_mem772 773 Description: Allocate PCM ring buffer for given substream774 775 Parameters: substream - PCM substream class776 hw_params - hardware parameters777 778 Returns: Error status779 780 ---------------------------------------------------------------------------*/781 782static int snd_trident_allocate_pcm_mem(struct snd_pcm_substream *substream,783 struct snd_pcm_hw_params *hw_params)784{785 struct snd_trident *trident = snd_pcm_substream_chip(substream);786 struct snd_pcm_runtime *runtime = substream->runtime;787 struct snd_trident_voice *voice = runtime->private_data;788 789 if (trident->tlb.entries) {790 if (runtime->buffer_changed) {791 if (voice->memblk)792 snd_trident_free_pages(trident, voice->memblk);793 voice->memblk = snd_trident_alloc_pages(trident, substream);794 if (voice->memblk == NULL)795 return -ENOMEM;796 }797 }798 return 0;799}800 801/*---------------------------------------------------------------------------802 snd_trident_allocate_evoice803 804 Description: Allocate extra voice as interrupt generator805 806 Parameters: substream - PCM substream class807 hw_params - hardware parameters808 809 Returns: Error status810 811 ---------------------------------------------------------------------------*/812 813static int snd_trident_allocate_evoice(struct snd_pcm_substream *substream,814 struct snd_pcm_hw_params *hw_params)815{816 struct snd_trident *trident = snd_pcm_substream_chip(substream);817 struct snd_pcm_runtime *runtime = substream->runtime;818 struct snd_trident_voice *voice = runtime->private_data;819 struct snd_trident_voice *evoice = voice->extra;820 821 /* voice management */822 823 if (params_buffer_size(hw_params) / 2 != params_period_size(hw_params)) {824 if (evoice == NULL) {825 evoice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);826 if (evoice == NULL)827 return -ENOMEM;828 voice->extra = evoice;829 evoice->substream = substream;830 }831 } else {832 if (evoice != NULL) {833 snd_trident_free_voice(trident, evoice);834 voice->extra = evoice = NULL;835 }836 }837 838 return 0;839}840 841/*---------------------------------------------------------------------------842 snd_trident_hw_params843 844 Description: Set the hardware parameters for the playback device.845 846 Parameters: substream - PCM substream class847 hw_params - hardware parameters848 849 Returns: Error status850 851 ---------------------------------------------------------------------------*/852 853static int snd_trident_hw_params(struct snd_pcm_substream *substream,854 struct snd_pcm_hw_params *hw_params)855{856 int err;857 858 err = snd_trident_allocate_pcm_mem(substream, hw_params);859 if (err >= 0)860 err = snd_trident_allocate_evoice(substream, hw_params);861 return err;862}863 864/*---------------------------------------------------------------------------865 snd_trident_playback_hw_free866 867 Description: Release the hardware resources for the playback device.868 869 Parameters: substream - PCM substream class870 871 Returns: Error status872 873 ---------------------------------------------------------------------------*/874 875static int snd_trident_hw_free(struct snd_pcm_substream *substream)876{877 struct snd_trident *trident = snd_pcm_substream_chip(substream);878 struct snd_pcm_runtime *runtime = substream->runtime;879 struct snd_trident_voice *voice = runtime->private_data;880 struct snd_trident_voice *evoice = voice ? voice->extra : NULL;881 882 if (trident->tlb.entries) {883 if (voice && voice->memblk) {884 snd_trident_free_pages(trident, voice->memblk);885 voice->memblk = NULL;886 }887 }888 if (evoice != NULL) {889 snd_trident_free_voice(trident, evoice);890 voice->extra = NULL;891 }892 return 0;893}894 895/*---------------------------------------------------------------------------896 snd_trident_playback_prepare897 898 Description: Prepare playback device for playback.899 900 Parameters: substream - PCM substream class901 902 Returns: Error status903 904 ---------------------------------------------------------------------------*/905 906static int snd_trident_playback_prepare(struct snd_pcm_substream *substream)907{908 struct snd_trident *trident = snd_pcm_substream_chip(substream);909 struct snd_pcm_runtime *runtime = substream->runtime;910 struct snd_trident_voice *voice = runtime->private_data;911 struct snd_trident_voice *evoice = voice->extra;912 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[substream->number];913 914 spin_lock_irq(&trident->reg_lock); 915 916 /* set delta (rate) value */917 voice->Delta = snd_trident_convert_rate(runtime->rate);918 voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);919 920 /* set Loop Begin Address */921 if (voice->memblk)922 voice->LBA = voice->memblk->offset;923 else924 voice->LBA = runtime->dma_addr;925 926 voice->CSO = 0;927 voice->ESO = runtime->buffer_size - 1; /* in samples */928 voice->CTRL = snd_trident_control_mode(substream);929 voice->FMC = 3;930 voice->GVSel = 1;931 voice->EC = 0;932 voice->Alpha = 0;933 voice->FMS = 0;934 voice->Vol = mix->vol;935 voice->RVol = mix->rvol;936 voice->CVol = mix->cvol;937 voice->Pan = mix->pan;938 voice->Attribute = 0;939#if 0940 voice->Attribute = (1<<(30-16))|(2<<(26-16))|941 (0<<(24-16))|(0x1f<<(19-16));942#else943 voice->Attribute = 0;944#endif945 946 snd_trident_write_voice_regs(trident, voice);947 948 if (evoice != NULL) {949 evoice->Delta = voice->Delta;950 evoice->spurious_threshold = voice->spurious_threshold;951 evoice->LBA = voice->LBA;952 evoice->CSO = 0;953 evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */954 evoice->CTRL = voice->CTRL;955 evoice->FMC = 3;956 evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;957 evoice->EC = 0;958 evoice->Alpha = 0;959 evoice->FMS = 0;960 evoice->Vol = 0x3ff; /* mute */961 evoice->RVol = evoice->CVol = 0x7f; /* mute */962 evoice->Pan = 0x7f; /* mute */963#if 0964 evoice->Attribute = (1<<(30-16))|(2<<(26-16))|965 (0<<(24-16))|(0x1f<<(19-16));966#else967 evoice->Attribute = 0;968#endif969 snd_trident_write_voice_regs(trident, evoice);970 evoice->isync2 = 1;971 evoice->isync_mark = runtime->period_size;972 evoice->ESO = (runtime->period_size * 2) - 1;973 }974 975 spin_unlock_irq(&trident->reg_lock);976 977 return 0;978}979 980/*---------------------------------------------------------------------------981 snd_trident_capture_hw_params982 983 Description: Set the hardware parameters for the capture device.984 985 Parameters: substream - PCM substream class986 hw_params - hardware parameters987 988 Returns: Error status989 990 ---------------------------------------------------------------------------*/991 992static int snd_trident_capture_hw_params(struct snd_pcm_substream *substream,993 struct snd_pcm_hw_params *hw_params)994{995 return snd_trident_allocate_pcm_mem(substream, hw_params);996}997 998/*---------------------------------------------------------------------------999 snd_trident_capture_prepare1000 1001 Description: Prepare capture device for playback.1002 1003 Parameters: substream - PCM substream class1004 1005 Returns: Error status1006 1007 ---------------------------------------------------------------------------*/1008 1009static int snd_trident_capture_prepare(struct snd_pcm_substream *substream)1010{1011 struct snd_trident *trident = snd_pcm_substream_chip(substream);1012 struct snd_pcm_runtime *runtime = substream->runtime;1013 struct snd_trident_voice *voice = runtime->private_data;1014 unsigned int val, ESO_bytes;1015 1016 spin_lock_irq(&trident->reg_lock);1017 1018 // Initialize the channel and set channel Mode1019 outb(0, TRID_REG(trident, LEGACY_DMAR15));1020 1021 // Set DMA channel operation mode register1022 outb(0x54, TRID_REG(trident, LEGACY_DMAR11));1023 1024 // Set channel buffer Address, DMAR0 expects contiguous PCI memory area 1025 voice->LBA = runtime->dma_addr;1026 outl(voice->LBA, TRID_REG(trident, LEGACY_DMAR0));1027 if (voice->memblk)1028 voice->LBA = voice->memblk->offset;1029 1030 // set ESO1031 ESO_bytes = snd_pcm_lib_buffer_bytes(substream) - 1;1032 outb((ESO_bytes & 0x00ff0000) >> 16, TRID_REG(trident, LEGACY_DMAR6));1033 outw((ESO_bytes & 0x0000ffff), TRID_REG(trident, LEGACY_DMAR4));1034 ESO_bytes++;1035 1036 // Set channel sample rate, 4.12 format1037 val = DIV_ROUND_CLOSEST(48000U << 12, runtime->rate);1038 outw(val, TRID_REG(trident, T4D_SBDELTA_DELTA_R));1039 1040 // Set channel interrupt blk length1041 if (snd_pcm_format_width(runtime->format) == 16) {1042 val = (unsigned short) ((ESO_bytes >> 1) - 1);1043 } else {1044 val = (unsigned short) (ESO_bytes - 1);1045 }1046 1047 outl((val << 16) | val, TRID_REG(trident, T4D_SBBL_SBCL));1048 1049 // Right now, set format and start to run captureing, 1050 // continuous run loop enable.1051 trident->bDMAStart = 0x19; // 0001 1001b1052 1053 if (snd_pcm_format_width(runtime->format) == 16)1054 trident->bDMAStart |= 0x80;1055 if (snd_pcm_format_signed(runtime->format))1056 trident->bDMAStart |= 0x20;1057 if (runtime->channels > 1)1058 trident->bDMAStart |= 0x40;1059 1060 // Prepare capture intr channel1061 1062 voice->Delta = snd_trident_convert_rate(runtime->rate);1063 voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);1064 voice->isync = 1;1065 voice->isync_mark = runtime->period_size;1066 voice->isync_max = runtime->buffer_size;1067 1068 // Set voice parameters1069 voice->CSO = 0;1070 voice->ESO = voice->isync_ESO = (runtime->period_size * 2) + 6 - 1;1071 voice->CTRL = snd_trident_control_mode(substream);1072 voice->FMC = 3;1073 voice->RVol = 0x7f;1074 voice->CVol = 0x7f;1075 voice->GVSel = 1;1076 voice->Pan = 0x7f; /* mute */1077 voice->Vol = 0x3ff; /* mute */1078 voice->EC = 0;1079 voice->Alpha = 0;1080 voice->FMS = 0;1081 voice->Attribute = 0;1082 1083 snd_trident_write_voice_regs(trident, voice);1084 1085 spin_unlock_irq(&trident->reg_lock);1086 return 0;1087}1088 1089/*---------------------------------------------------------------------------1090 snd_trident_si7018_capture_hw_params1091 1092 Description: Set the hardware parameters for the capture device.1093 1094 Parameters: substream - PCM substream class1095 hw_params - hardware parameters1096 1097 Returns: Error status1098 1099 ---------------------------------------------------------------------------*/1100 1101static int snd_trident_si7018_capture_hw_params(struct snd_pcm_substream *substream,1102 struct snd_pcm_hw_params *hw_params)1103{1104 return snd_trident_allocate_evoice(substream, hw_params);1105}1106 1107/*---------------------------------------------------------------------------1108 snd_trident_si7018_capture_hw_free1109 1110 Description: Release the hardware resources for the capture device.1111 1112 Parameters: substream - PCM substream class1113 1114 Returns: Error status1115 1116 ---------------------------------------------------------------------------*/1117 1118static int snd_trident_si7018_capture_hw_free(struct snd_pcm_substream *substream)1119{1120 struct snd_trident *trident = snd_pcm_substream_chip(substream);1121 struct snd_pcm_runtime *runtime = substream->runtime;1122 struct snd_trident_voice *voice = runtime->private_data;1123 struct snd_trident_voice *evoice = voice ? voice->extra : NULL;1124 1125 if (evoice != NULL) {1126 snd_trident_free_voice(trident, evoice);1127 voice->extra = NULL;1128 }1129 return 0;1130}1131 1132/*---------------------------------------------------------------------------1133 snd_trident_si7018_capture_prepare1134 1135 Description: Prepare capture device for playback.1136 1137 Parameters: substream - PCM substream class1138 1139 Returns: Error status1140 1141 ---------------------------------------------------------------------------*/1142 1143static int snd_trident_si7018_capture_prepare(struct snd_pcm_substream *substream)1144{1145 struct snd_trident *trident = snd_pcm_substream_chip(substream);1146 struct snd_pcm_runtime *runtime = substream->runtime;1147 struct snd_trident_voice *voice = runtime->private_data;1148 struct snd_trident_voice *evoice = voice->extra;1149 1150 spin_lock_irq(&trident->reg_lock);1151 1152 voice->LBA = runtime->dma_addr;1153 voice->Delta = snd_trident_convert_adc_rate(runtime->rate);1154 voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);1155 1156 // Set voice parameters1157 voice->CSO = 0;1158 voice->ESO = runtime->buffer_size - 1; /* in samples */1159 voice->CTRL = snd_trident_control_mode(substream);1160 voice->FMC = 0;1161 voice->RVol = 0;1162 voice->CVol = 0;1163 voice->GVSel = 1;1164 voice->Pan = T4D_DEFAULT_PCM_PAN;1165 voice->Vol = 0;1166 voice->EC = 0;1167 voice->Alpha = 0;1168 voice->FMS = 0;1169 1170 voice->Attribute = (2 << (30-16)) |1171 (2 << (26-16)) |1172 (2 << (24-16)) |1173 (1 << (23-16));1174 1175 snd_trident_write_voice_regs(trident, voice);1176 1177 if (evoice != NULL) {1178 evoice->Delta = snd_trident_convert_rate(runtime->rate);1179 evoice->spurious_threshold = voice->spurious_threshold;1180 evoice->LBA = voice->LBA;1181 evoice->CSO = 0;1182 evoice->ESO = (runtime->period_size * 2) + 20 - 1; /* in samples, 20 means correction */1183 evoice->CTRL = voice->CTRL;1184 evoice->FMC = 3;1185 evoice->GVSel = 0;1186 evoice->EC = 0;1187 evoice->Alpha = 0;1188 evoice->FMS = 0;1189 evoice->Vol = 0x3ff; /* mute */1190 evoice->RVol = evoice->CVol = 0x7f; /* mute */1191 evoice->Pan = 0x7f; /* mute */1192 evoice->Attribute = 0;1193 snd_trident_write_voice_regs(trident, evoice);1194 evoice->isync2 = 1;1195 evoice->isync_mark = runtime->period_size;1196 evoice->ESO = (runtime->period_size * 2) - 1;1197 }1198 1199 spin_unlock_irq(&trident->reg_lock);1200 return 0;1201}1202 1203/*---------------------------------------------------------------------------1204 snd_trident_foldback_prepare1205 1206 Description: Prepare foldback capture device for playback.1207 1208 Parameters: substream - PCM substream class1209 1210 Returns: Error status1211 1212 ---------------------------------------------------------------------------*/1213 1214static int snd_trident_foldback_prepare(struct snd_pcm_substream *substream)1215{1216 struct snd_trident *trident = snd_pcm_substream_chip(substream);1217 struct snd_pcm_runtime *runtime = substream->runtime;1218 struct snd_trident_voice *voice = runtime->private_data;1219 struct snd_trident_voice *evoice = voice->extra;1220 1221 spin_lock_irq(&trident->reg_lock);1222 1223 /* Set channel buffer Address */1224 if (voice->memblk)1225 voice->LBA = voice->memblk->offset;1226 else1227 voice->LBA = runtime->dma_addr;1228 1229 /* set target ESO for channel */1230 voice->ESO = runtime->buffer_size - 1; /* in samples */1231 1232 /* set sample rate */1233 voice->Delta = 0x1000;1234 voice->spurious_threshold = snd_trident_spurious_threshold(48000, runtime->period_size);1235 1236 voice->CSO = 0;1237 voice->CTRL = snd_trident_control_mode(substream);1238 voice->FMC = 3;1239 voice->RVol = 0x7f;1240 voice->CVol = 0x7f;1241 voice->GVSel = 1;1242 voice->Pan = 0x7f; /* mute */1243 voice->Vol = 0x3ff; /* mute */1244 voice->EC = 0;1245 voice->Alpha = 0;1246 voice->FMS = 0;1247 voice->Attribute = 0;1248 1249 /* set up capture channel */1250 outb(((voice->number & 0x3f) | 0x80), TRID_REG(trident, T4D_RCI + voice->foldback_chan));1251 1252 snd_trident_write_voice_regs(trident, voice);1253 1254 if (evoice != NULL) {1255 evoice->Delta = voice->Delta;1256 evoice->spurious_threshold = voice->spurious_threshold;1257 evoice->LBA = voice->LBA;1258 evoice->CSO = 0;1259 evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */1260 evoice->CTRL = voice->CTRL;1261 evoice->FMC = 3;1262 evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;1263 evoice->EC = 0;1264 evoice->Alpha = 0;1265 evoice->FMS = 0;1266 evoice->Vol = 0x3ff; /* mute */1267 evoice->RVol = evoice->CVol = 0x7f; /* mute */1268 evoice->Pan = 0x7f; /* mute */1269 evoice->Attribute = 0;1270 snd_trident_write_voice_regs(trident, evoice);1271 evoice->isync2 = 1;1272 evoice->isync_mark = runtime->period_size;1273 evoice->ESO = (runtime->period_size * 2) - 1;1274 }1275 1276 spin_unlock_irq(&trident->reg_lock);1277 return 0;1278}1279 1280/*---------------------------------------------------------------------------1281 snd_trident_spdif_hw_params1282 1283 Description: Set the hardware parameters for the spdif device.1284 1285 Parameters: substream - PCM substream class1286 hw_params - hardware parameters1287 1288 Returns: Error status1289 1290 ---------------------------------------------------------------------------*/1291 1292static int snd_trident_spdif_hw_params(struct snd_pcm_substream *substream,1293 struct snd_pcm_hw_params *hw_params)1294{1295 struct snd_trident *trident = snd_pcm_substream_chip(substream);1296 unsigned int old_bits = 0, change = 0;1297 int err;1298 1299 err = snd_trident_allocate_pcm_mem(substream, hw_params);1300 if (err < 0)1301 return err;1302 1303 if (trident->device == TRIDENT_DEVICE_ID_SI7018) {1304 err = snd_trident_allocate_evoice(substream, hw_params);1305 if (err < 0)1306 return err;1307 }1308 1309 /* prepare SPDIF channel */1310 spin_lock_irq(&trident->reg_lock);1311 old_bits = trident->spdif_pcm_bits;1312 if (old_bits & IEC958_AES0_PROFESSIONAL)1313 trident->spdif_pcm_bits &= ~IEC958_AES0_PRO_FS;1314 else1315 trident->spdif_pcm_bits &= ~(IEC958_AES3_CON_FS << 24);1316 if (params_rate(hw_params) >= 48000) {1317 trident->spdif_pcm_ctrl = 0x3c; // 48000 Hz1318 trident->spdif_pcm_bits |=1319 trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?1320 IEC958_AES0_PRO_FS_48000 :1321 (IEC958_AES3_CON_FS_48000 << 24);1322 }1323 else if (params_rate(hw_params) >= 44100) {1324 trident->spdif_pcm_ctrl = 0x3e; // 44100 Hz1325 trident->spdif_pcm_bits |=1326 trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?1327 IEC958_AES0_PRO_FS_44100 :1328 (IEC958_AES3_CON_FS_44100 << 24);1329 }1330 else {1331 trident->spdif_pcm_ctrl = 0x3d; // 32000 Hz1332 trident->spdif_pcm_bits |=1333 trident->spdif_bits & IEC958_AES0_PROFESSIONAL ?1334 IEC958_AES0_PRO_FS_32000 :1335 (IEC958_AES3_CON_FS_32000 << 24);1336 }1337 change = old_bits != trident->spdif_pcm_bits;1338 spin_unlock_irq(&trident->reg_lock);1339 1340 if (change)1341 snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE, &trident->spdif_pcm_ctl->id);1342 1343 return 0;1344}1345 1346/*---------------------------------------------------------------------------1347 snd_trident_spdif_prepare1348 1349 Description: Prepare SPDIF device for playback.1350 1351 Parameters: substream - PCM substream class1352 1353 Returns: Error status1354 1355 ---------------------------------------------------------------------------*/1356 1357static int snd_trident_spdif_prepare(struct snd_pcm_substream *substream)1358{1359 struct snd_trident *trident = snd_pcm_substream_chip(substream);1360 struct snd_pcm_runtime *runtime = substream->runtime;1361 struct snd_trident_voice *voice = runtime->private_data;1362 struct snd_trident_voice *evoice = voice->extra;1363 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[substream->number];1364 unsigned int RESO, LBAO;1365 unsigned int temp;1366 1367 spin_lock_irq(&trident->reg_lock);1368 1369 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {1370 1371 /* set delta (rate) value */1372 voice->Delta = snd_trident_convert_rate(runtime->rate);1373 voice->spurious_threshold = snd_trident_spurious_threshold(runtime->rate, runtime->period_size);1374 1375 /* set Loop Back Address */1376 LBAO = runtime->dma_addr;1377 if (voice->memblk)1378 voice->LBA = voice->memblk->offset;1379 else1380 voice->LBA = LBAO;1381 1382 voice->isync = 1;1383 voice->isync3 = 1;1384 voice->isync_mark = runtime->period_size;1385 voice->isync_max = runtime->buffer_size;1386 1387 /* set target ESO for channel */1388 RESO = runtime->buffer_size - 1;1389 voice->ESO = voice->isync_ESO = (runtime->period_size * 2) + 6 - 1;1390 1391 /* set ctrl mode */1392 voice->CTRL = snd_trident_control_mode(substream);1393 1394 voice->FMC = 3;1395 voice->RVol = 0x7f;1396 voice->CVol = 0x7f;1397 voice->GVSel = 1;1398 voice->Pan = 0x7f;1399 voice->Vol = 0x3ff;1400 voice->EC = 0;1401 voice->CSO = 0;1402 voice->Alpha = 0;1403 voice->FMS = 0;1404 voice->Attribute = 0;1405 1406 /* prepare surrogate IRQ channel */1407 snd_trident_write_voice_regs(trident, voice);1408 1409 outw((RESO & 0xffff), TRID_REG(trident, NX_SPESO));1410 outb((RESO >> 16), TRID_REG(trident, NX_SPESO + 2));1411 outl((LBAO & 0xfffffffc), TRID_REG(trident, NX_SPLBA));1412 outw((voice->CSO & 0xffff), TRID_REG(trident, NX_SPCTRL_SPCSO));1413 outb((voice->CSO >> 16), TRID_REG(trident, NX_SPCTRL_SPCSO + 2));1414 1415 /* set SPDIF setting */1416 outb(trident->spdif_pcm_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));1417 outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));1418 1419 } else { /* SiS */1420 1421 /* set delta (rate) value */1422 voice->Delta = 0x800;1423 voice->spurious_threshold = snd_trident_spurious_threshold(48000, runtime->period_size);1424 1425 /* set Loop Begin Address */1426 if (voice->memblk)1427 voice->LBA = voice->memblk->offset;1428 else1429 voice->LBA = runtime->dma_addr;1430 1431 voice->CSO = 0;1432 voice->ESO = runtime->buffer_size - 1; /* in samples */1433 voice->CTRL = snd_trident_control_mode(substream);1434 voice->FMC = 3;1435 voice->GVSel = 1;1436 voice->EC = 0;1437 voice->Alpha = 0;1438 voice->FMS = 0;1439 voice->Vol = mix->vol;1440 voice->RVol = mix->rvol;1441 voice->CVol = mix->cvol;1442 voice->Pan = mix->pan;1443 voice->Attribute = (1<<(30-16))|(7<<(26-16))|1444 (0<<(24-16))|(0<<(19-16));1445 1446 snd_trident_write_voice_regs(trident, voice);1447 1448 if (evoice != NULL) {1449 evoice->Delta = voice->Delta;1450 evoice->spurious_threshold = voice->spurious_threshold;1451 evoice->LBA = voice->LBA;1452 evoice->CSO = 0;1453 evoice->ESO = (runtime->period_size * 2) + 4 - 1; /* in samples */1454 evoice->CTRL = voice->CTRL;1455 evoice->FMC = 3;1456 evoice->GVSel = trident->device == TRIDENT_DEVICE_ID_SI7018 ? 0 : 1;1457 evoice->EC = 0;1458 evoice->Alpha = 0;1459 evoice->FMS = 0;1460 evoice->Vol = 0x3ff; /* mute */1461 evoice->RVol = evoice->CVol = 0x7f; /* mute */1462 evoice->Pan = 0x7f; /* mute */1463 evoice->Attribute = 0;1464 snd_trident_write_voice_regs(trident, evoice);1465 evoice->isync2 = 1;1466 evoice->isync_mark = runtime->period_size;1467 evoice->ESO = (runtime->period_size * 2) - 1;1468 }1469 1470 outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));1471 temp = inl(TRID_REG(trident, T4D_LFO_GC_CIR));1472 temp &= ~(1<<19);1473 outl(temp, TRID_REG(trident, T4D_LFO_GC_CIR));1474 temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL));1475 temp |= SPDIF_EN;1476 outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));1477 }1478 1479 spin_unlock_irq(&trident->reg_lock);1480 1481 return 0;1482}1483 1484/*---------------------------------------------------------------------------1485 snd_trident_trigger1486 1487 Description: Start/stop devices1488 1489 Parameters: substream - PCM substream class1490 cmd - trigger command (STOP, GO)1491 1492 Returns: Error status1493 1494 ---------------------------------------------------------------------------*/1495 1496static int snd_trident_trigger(struct snd_pcm_substream *substream,1497 int cmd)1498 1499{1500 struct snd_trident *trident = snd_pcm_substream_chip(substream);1501 struct snd_pcm_substream *s;1502 unsigned int what, whati, capture_flag, spdif_flag;1503 struct snd_trident_voice *voice, *evoice;1504 unsigned int val, go;1505 1506 switch (cmd) {1507 case SNDRV_PCM_TRIGGER_START:1508 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:1509 case SNDRV_PCM_TRIGGER_RESUME:1510 go = 1;1511 break;1512 case SNDRV_PCM_TRIGGER_STOP:1513 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:1514 case SNDRV_PCM_TRIGGER_SUSPEND:1515 go = 0;1516 break;1517 default:1518 return -EINVAL;1519 }1520 what = whati = capture_flag = spdif_flag = 0;1521 spin_lock(&trident->reg_lock);1522 val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff;1523 snd_pcm_group_for_each_entry(s, substream) {1524 if ((struct snd_trident *) snd_pcm_substream_chip(s) == trident) {1525 voice = s->runtime->private_data;1526 evoice = voice->extra;1527 what |= 1 << (voice->number & 0x1f);1528 if (evoice == NULL) {1529 whati |= 1 << (voice->number & 0x1f);1530 } else {1531 what |= 1 << (evoice->number & 0x1f);1532 whati |= 1 << (evoice->number & 0x1f);1533 if (go)1534 evoice->stimer = val;1535 }1536 if (go) {1537 voice->running = 1;1538 voice->stimer = val;1539 } else {1540 voice->running = 0;1541 }1542 snd_pcm_trigger_done(s, substream);1543 if (voice->capture)1544 capture_flag = 1;1545 if (voice->spdif)1546 spdif_flag = 1;1547 }1548 }1549 if (spdif_flag) {1550 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {1551 outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));1552 val = trident->spdif_pcm_ctrl;1553 if (!go)1554 val &= ~(0x28);1555 outb(val, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));1556 } else {1557 outl(trident->spdif_pcm_bits, TRID_REG(trident, SI_SPDIF_CS));1558 val = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) | SPDIF_EN;1559 outl(val, TRID_REG(trident, SI_SERIAL_INTF_CTRL));1560 }1561 }1562 if (!go)1563 outl(what, TRID_REG(trident, T4D_STOP_B));1564 val = inl(TRID_REG(trident, T4D_AINTEN_B));1565 if (go) {1566 val |= whati;1567 } else {1568 val &= ~whati;1569 }1570 outl(val, TRID_REG(trident, T4D_AINTEN_B));1571 if (go) {1572 outl(what, TRID_REG(trident, T4D_START_B));1573 1574 if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018)1575 outb(trident->bDMAStart, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));1576 } else {1577 if (capture_flag && trident->device != TRIDENT_DEVICE_ID_SI7018)1578 outb(0x00, TRID_REG(trident, T4D_SBCTRL_SBE2R_SBDD));1579 }1580 spin_unlock(&trident->reg_lock);1581 return 0;1582}1583 1584/*---------------------------------------------------------------------------1585 snd_trident_playback_pointer1586 1587 Description: This routine return the playback position1588 1589 Parameters: substream - PCM substream class1590 1591 Returns: position of buffer1592 1593 ---------------------------------------------------------------------------*/1594 1595static snd_pcm_uframes_t snd_trident_playback_pointer(struct snd_pcm_substream *substream)1596{1597 struct snd_trident *trident = snd_pcm_substream_chip(substream);1598 struct snd_pcm_runtime *runtime = substream->runtime;1599 struct snd_trident_voice *voice = runtime->private_data;1600 unsigned int cso;1601 1602 if (!voice->running)1603 return 0;1604 1605 spin_lock(&trident->reg_lock);1606 1607 outb(voice->number, TRID_REG(trident, T4D_LFO_GC_CIR));1608 1609 if (trident->device != TRIDENT_DEVICE_ID_NX) {1610 cso = inw(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS + 2));1611 } else { // ID_4DWAVE_NX1612 cso = (unsigned int) inl(TRID_REG(trident, CH_NX_DELTA_CSO)) & 0x00ffffff;1613 }1614 1615 spin_unlock(&trident->reg_lock);1616 1617 if (cso >= runtime->buffer_size)1618 cso = 0;1619 1620 return cso;1621}1622 1623/*---------------------------------------------------------------------------1624 snd_trident_capture_pointer1625 1626 Description: This routine return the capture position1627 1628 Parameters: pcm1 - PCM device class1629 1630 Returns: position of buffer1631 1632 ---------------------------------------------------------------------------*/1633 1634static snd_pcm_uframes_t snd_trident_capture_pointer(struct snd_pcm_substream *substream)1635{1636 struct snd_trident *trident = snd_pcm_substream_chip(substream);1637 struct snd_pcm_runtime *runtime = substream->runtime;1638 struct snd_trident_voice *voice = runtime->private_data;1639 unsigned int result;1640 1641 if (!voice->running)1642 return 0;1643 1644 result = inw(TRID_REG(trident, T4D_SBBL_SBCL));1645 if (runtime->channels > 1)1646 result >>= 1;1647 if (result > 0)1648 result = runtime->buffer_size - result;1649 1650 return result;1651}1652 1653/*---------------------------------------------------------------------------1654 snd_trident_spdif_pointer1655 1656 Description: This routine return the SPDIF playback position1657 1658 Parameters: substream - PCM substream class1659 1660 Returns: position of buffer1661 1662 ---------------------------------------------------------------------------*/1663 1664static snd_pcm_uframes_t snd_trident_spdif_pointer(struct snd_pcm_substream *substream)1665{1666 struct snd_trident *trident = snd_pcm_substream_chip(substream);1667 struct snd_pcm_runtime *runtime = substream->runtime;1668 struct snd_trident_voice *voice = runtime->private_data;1669 unsigned int result;1670 1671 if (!voice->running)1672 return 0;1673 1674 result = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff;1675 1676 return result;1677}1678 1679/*1680 * Playback support device description1681 */1682 1683static const struct snd_pcm_hardware snd_trident_playback =1684{1685 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |1686 SNDRV_PCM_INFO_BLOCK_TRANSFER |1687 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |1688 SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),1689 .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |1690 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),1691 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,1692 .rate_min = 4000,1693 .rate_max = 48000,1694 .channels_min = 1,1695 .channels_max = 2,1696 .buffer_bytes_max = (256*1024),1697 .period_bytes_min = 64,1698 .period_bytes_max = (256*1024),1699 .periods_min = 1,1700 .periods_max = 1024,1701 .fifo_size = 0,1702};1703 1704/*1705 * Capture support device description1706 */1707 1708static const struct snd_pcm_hardware snd_trident_capture =1709{1710 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |1711 SNDRV_PCM_INFO_BLOCK_TRANSFER |1712 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |1713 SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),1714 .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |1715 SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE),1716 .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,1717 .rate_min = 4000,1718 .rate_max = 48000,1719 .channels_min = 1,1720 .channels_max = 2,1721 .buffer_bytes_max = (128*1024),1722 .period_bytes_min = 64,1723 .period_bytes_max = (128*1024),1724 .periods_min = 1,1725 .periods_max = 1024,1726 .fifo_size = 0,1727};1728 1729/*1730 * Foldback capture support device description1731 */1732 1733static const struct snd_pcm_hardware snd_trident_foldback =1734{1735 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |1736 SNDRV_PCM_INFO_BLOCK_TRANSFER |1737 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |1738 SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),1739 .formats = SNDRV_PCM_FMTBIT_S16_LE,1740 .rates = SNDRV_PCM_RATE_48000,1741 .rate_min = 48000,1742 .rate_max = 48000,1743 .channels_min = 2,1744 .channels_max = 2,1745 .buffer_bytes_max = (128*1024),1746 .period_bytes_min = 64,1747 .period_bytes_max = (128*1024),1748 .periods_min = 1,1749 .periods_max = 1024,1750 .fifo_size = 0,1751};1752 1753/*1754 * SPDIF playback support device description1755 */1756 1757static const struct snd_pcm_hardware snd_trident_spdif =1758{1759 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |1760 SNDRV_PCM_INFO_BLOCK_TRANSFER |1761 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |1762 SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),1763 .formats = SNDRV_PCM_FMTBIT_S16_LE,1764 .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |1765 SNDRV_PCM_RATE_48000),1766 .rate_min = 32000,1767 .rate_max = 48000,1768 .channels_min = 2,1769 .channels_max = 2,1770 .buffer_bytes_max = (128*1024),1771 .period_bytes_min = 64,1772 .period_bytes_max = (128*1024),1773 .periods_min = 1,1774 .periods_max = 1024,1775 .fifo_size = 0,1776};1777 1778static const struct snd_pcm_hardware snd_trident_spdif_7018 =1779{1780 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |1781 SNDRV_PCM_INFO_BLOCK_TRANSFER |1782 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START |1783 SNDRV_PCM_INFO_PAUSE /* | SNDRV_PCM_INFO_RESUME */),1784 .formats = SNDRV_PCM_FMTBIT_S16_LE,1785 .rates = SNDRV_PCM_RATE_48000,1786 .rate_min = 48000,1787 .rate_max = 48000,1788 .channels_min = 2,1789 .channels_max = 2,1790 .buffer_bytes_max = (128*1024),1791 .period_bytes_min = 64,1792 .period_bytes_max = (128*1024),1793 .periods_min = 1,1794 .periods_max = 1024,1795 .fifo_size = 0,1796};1797 1798static void snd_trident_pcm_free_substream(struct snd_pcm_runtime *runtime)1799{1800 struct snd_trident_voice *voice = runtime->private_data;1801 struct snd_trident *trident;1802 1803 if (voice) {1804 trident = voice->trident;1805 snd_trident_free_voice(trident, voice);1806 }1807}1808 1809static int snd_trident_playback_open(struct snd_pcm_substream *substream)1810{1811 struct snd_trident *trident = snd_pcm_substream_chip(substream);1812 struct snd_pcm_runtime *runtime = substream->runtime;1813 struct snd_trident_voice *voice;1814 1815 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);1816 if (voice == NULL)1817 return -EAGAIN;1818 snd_trident_pcm_mixer_build(trident, voice, substream);1819 voice->substream = substream;1820 runtime->private_data = voice;1821 runtime->private_free = snd_trident_pcm_free_substream;1822 runtime->hw = snd_trident_playback;1823 snd_pcm_set_sync(substream);1824 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);1825 return 0;1826}1827 1828/*---------------------------------------------------------------------------1829 snd_trident_playback_close1830 1831 Description: This routine will close the 4DWave playback device. For now 1832 we will simply free the dma transfer buffer.1833 1834 Parameters: substream - PCM substream class1835 1836 ---------------------------------------------------------------------------*/1837static int snd_trident_playback_close(struct snd_pcm_substream *substream)1838{1839 struct snd_trident *trident = snd_pcm_substream_chip(substream);1840 struct snd_pcm_runtime *runtime = substream->runtime;1841 struct snd_trident_voice *voice = runtime->private_data;1842 1843 snd_trident_pcm_mixer_free(trident, voice, substream);1844 return 0;1845}1846 1847/*---------------------------------------------------------------------------1848 snd_trident_spdif_open1849 1850 Description: This routine will open the 4DWave SPDIF device.1851 1852 Parameters: substream - PCM substream class1853 1854 Returns: status - success or failure flag1855 1856 ---------------------------------------------------------------------------*/1857 1858static int snd_trident_spdif_open(struct snd_pcm_substream *substream)1859{1860 struct snd_trident *trident = snd_pcm_substream_chip(substream);1861 struct snd_trident_voice *voice;1862 struct snd_pcm_runtime *runtime = substream->runtime;1863 1864 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);1865 if (voice == NULL)1866 return -EAGAIN;1867 voice->spdif = 1;1868 voice->substream = substream;1869 spin_lock_irq(&trident->reg_lock);1870 trident->spdif_pcm_bits = trident->spdif_bits;1871 spin_unlock_irq(&trident->reg_lock);1872 1873 runtime->private_data = voice;1874 runtime->private_free = snd_trident_pcm_free_substream;1875 if (trident->device == TRIDENT_DEVICE_ID_SI7018) {1876 runtime->hw = snd_trident_spdif;1877 } else {1878 runtime->hw = snd_trident_spdif_7018;1879 }1880 1881 trident->spdif_pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;1882 snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |1883 SNDRV_CTL_EVENT_MASK_INFO, &trident->spdif_pcm_ctl->id);1884 1885 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);1886 return 0;1887}1888 1889 1890/*---------------------------------------------------------------------------1891 snd_trident_spdif_close1892 1893 Description: This routine will close the 4DWave SPDIF device.1894 1895 Parameters: substream - PCM substream class1896 1897 ---------------------------------------------------------------------------*/1898 1899static int snd_trident_spdif_close(struct snd_pcm_substream *substream)1900{1901 struct snd_trident *trident = snd_pcm_substream_chip(substream);1902 unsigned int temp;1903 1904 spin_lock_irq(&trident->reg_lock);1905 // restore default SPDIF setting1906 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {1907 outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));1908 outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));1909 } else {1910 outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));1911 temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL));1912 if (trident->spdif_ctrl) {1913 temp |= SPDIF_EN;1914 } else {1915 temp &= ~SPDIF_EN;1916 }1917 outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));1918 }1919 spin_unlock_irq(&trident->reg_lock);1920 trident->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;1921 snd_ctl_notify(trident->card, SNDRV_CTL_EVENT_MASK_VALUE |1922 SNDRV_CTL_EVENT_MASK_INFO, &trident->spdif_pcm_ctl->id);1923 return 0;1924}1925 1926/*---------------------------------------------------------------------------1927 snd_trident_capture_open1928 1929 Description: This routine will open the 4DWave capture device.1930 1931 Parameters: substream - PCM substream class1932 1933 Returns: status - success or failure flag1934 1935 ---------------------------------------------------------------------------*/1936 1937static int snd_trident_capture_open(struct snd_pcm_substream *substream)1938{1939 struct snd_trident *trident = snd_pcm_substream_chip(substream);1940 struct snd_trident_voice *voice;1941 struct snd_pcm_runtime *runtime = substream->runtime;1942 1943 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);1944 if (voice == NULL)1945 return -EAGAIN;1946 voice->capture = 1;1947 voice->substream = substream;1948 runtime->private_data = voice;1949 runtime->private_free = snd_trident_pcm_free_substream;1950 runtime->hw = snd_trident_capture;1951 snd_pcm_set_sync(substream);1952 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);1953 return 0;1954}1955 1956/*---------------------------------------------------------------------------1957 snd_trident_capture_close1958 1959 Description: This routine will close the 4DWave capture device. For now 1960 we will simply free the dma transfer buffer.1961 1962 Parameters: substream - PCM substream class1963 1964 ---------------------------------------------------------------------------*/1965static int snd_trident_capture_close(struct snd_pcm_substream *substream)1966{1967 return 0;1968}1969 1970/*---------------------------------------------------------------------------1971 snd_trident_foldback_open1972 1973 Description: This routine will open the 4DWave foldback capture device.1974 1975 Parameters: substream - PCM substream class1976 1977 Returns: status - success or failure flag1978 1979 ---------------------------------------------------------------------------*/1980 1981static int snd_trident_foldback_open(struct snd_pcm_substream *substream)1982{1983 struct snd_trident *trident = snd_pcm_substream_chip(substream);1984 struct snd_trident_voice *voice;1985 struct snd_pcm_runtime *runtime = substream->runtime;1986 1987 voice = snd_trident_alloc_voice(trident, SNDRV_TRIDENT_VOICE_TYPE_PCM, 0, 0);1988 if (voice == NULL)1989 return -EAGAIN;1990 voice->foldback_chan = substream->number;1991 voice->substream = substream;1992 runtime->private_data = voice;1993 runtime->private_free = snd_trident_pcm_free_substream;1994 runtime->hw = snd_trident_foldback;1995 snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 64*1024);1996 return 0;1997}1998 1999/*---------------------------------------------------------------------------2000 snd_trident_foldback_close2001 2002 Description: This routine will close the 4DWave foldback capture device. 2003 For now we will simply free the dma transfer buffer.2004 2005 Parameters: substream - PCM substream class2006 2007 ---------------------------------------------------------------------------*/2008static int snd_trident_foldback_close(struct snd_pcm_substream *substream)2009{2010 struct snd_trident *trident = snd_pcm_substream_chip(substream);2011 struct snd_trident_voice *voice;2012 struct snd_pcm_runtime *runtime = substream->runtime;2013 voice = runtime->private_data;2014 2015 /* stop capture channel */2016 spin_lock_irq(&trident->reg_lock);2017 outb(0x00, TRID_REG(trident, T4D_RCI + voice->foldback_chan));2018 spin_unlock_irq(&trident->reg_lock);2019 return 0;2020}2021 2022/*---------------------------------------------------------------------------2023 PCM operations2024 ---------------------------------------------------------------------------*/2025 2026static const struct snd_pcm_ops snd_trident_playback_ops = {2027 .open = snd_trident_playback_open,2028 .close = snd_trident_playback_close,2029 .hw_params = snd_trident_hw_params,2030 .hw_free = snd_trident_hw_free,2031 .prepare = snd_trident_playback_prepare,2032 .trigger = snd_trident_trigger,2033 .pointer = snd_trident_playback_pointer,2034};2035 2036static const struct snd_pcm_ops snd_trident_nx_playback_ops = {2037 .open = snd_trident_playback_open,2038 .close = snd_trident_playback_close,2039 .hw_params = snd_trident_hw_params,2040 .hw_free = snd_trident_hw_free,2041 .prepare = snd_trident_playback_prepare,2042 .trigger = snd_trident_trigger,2043 .pointer = snd_trident_playback_pointer,2044};2045 2046static const struct snd_pcm_ops snd_trident_capture_ops = {2047 .open = snd_trident_capture_open,2048 .close = snd_trident_capture_close,2049 .hw_params = snd_trident_capture_hw_params,2050 .hw_free = snd_trident_hw_free,2051 .prepare = snd_trident_capture_prepare,2052 .trigger = snd_trident_trigger,2053 .pointer = snd_trident_capture_pointer,2054};2055 2056static const struct snd_pcm_ops snd_trident_si7018_capture_ops = {2057 .open = snd_trident_capture_open,2058 .close = snd_trident_capture_close,2059 .hw_params = snd_trident_si7018_capture_hw_params,2060 .hw_free = snd_trident_si7018_capture_hw_free,2061 .prepare = snd_trident_si7018_capture_prepare,2062 .trigger = snd_trident_trigger,2063 .pointer = snd_trident_playback_pointer,2064};2065 2066static const struct snd_pcm_ops snd_trident_foldback_ops = {2067 .open = snd_trident_foldback_open,2068 .close = snd_trident_foldback_close,2069 .hw_params = snd_trident_hw_params,2070 .hw_free = snd_trident_hw_free,2071 .prepare = snd_trident_foldback_prepare,2072 .trigger = snd_trident_trigger,2073 .pointer = snd_trident_playback_pointer,2074};2075 2076static const struct snd_pcm_ops snd_trident_nx_foldback_ops = {2077 .open = snd_trident_foldback_open,2078 .close = snd_trident_foldback_close,2079 .hw_params = snd_trident_hw_params,2080 .hw_free = snd_trident_hw_free,2081 .prepare = snd_trident_foldback_prepare,2082 .trigger = snd_trident_trigger,2083 .pointer = snd_trident_playback_pointer,2084};2085 2086static const struct snd_pcm_ops snd_trident_spdif_ops = {2087 .open = snd_trident_spdif_open,2088 .close = snd_trident_spdif_close,2089 .hw_params = snd_trident_spdif_hw_params,2090 .hw_free = snd_trident_hw_free,2091 .prepare = snd_trident_spdif_prepare,2092 .trigger = snd_trident_trigger,2093 .pointer = snd_trident_spdif_pointer,2094};2095 2096static const struct snd_pcm_ops snd_trident_spdif_7018_ops = {2097 .open = snd_trident_spdif_open,2098 .close = snd_trident_spdif_close,2099 .hw_params = snd_trident_spdif_hw_params,2100 .hw_free = snd_trident_hw_free,2101 .prepare = snd_trident_spdif_prepare,2102 .trigger = snd_trident_trigger,2103 .pointer = snd_trident_playback_pointer,2104};2105 2106/*---------------------------------------------------------------------------2107 snd_trident_pcm2108 2109 Description: This routine registers the 4DWave device for PCM support.2110 2111 Parameters: trident - pointer to target device class for 4DWave.2112 2113 Returns: None2114 2115 ---------------------------------------------------------------------------*/2116 2117int snd_trident_pcm(struct snd_trident *trident, int device)2118{2119 struct snd_pcm *pcm;2120 int err;2121 2122 err = snd_pcm_new(trident->card, "trident_dx_nx", device, trident->ChanPCM, 1, &pcm);2123 if (err < 0)2124 return err;2125 2126 pcm->private_data = trident;2127 2128 if (trident->tlb.entries) {2129 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_nx_playback_ops);2130 } else {2131 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_playback_ops);2132 }2133 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,2134 trident->device != TRIDENT_DEVICE_ID_SI7018 ?2135 &snd_trident_capture_ops :2136 &snd_trident_si7018_capture_ops);2137 2138 pcm->info_flags = 0;2139 pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;2140 strcpy(pcm->name, "Trident 4DWave");2141 trident->pcm = pcm;2142 2143 if (trident->tlb.entries) {2144 struct snd_pcm_substream *substream;2145 for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next)2146 snd_pcm_set_managed_buffer(substream, SNDRV_DMA_TYPE_DEV_SG,2147 &trident->pci->dev,2148 64*1024, 128*1024);2149 snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,2150 SNDRV_DMA_TYPE_DEV,2151 &trident->pci->dev,2152 64*1024, 128*1024);2153 } else {2154 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,2155 &trident->pci->dev,2156 64*1024, 128*1024);2157 }2158 2159 return 0;2160}2161 2162/*---------------------------------------------------------------------------2163 snd_trident_foldback_pcm2164 2165 Description: This routine registers the 4DWave device for foldback PCM support.2166 2167 Parameters: trident - pointer to target device class for 4DWave.2168 2169 Returns: None2170 2171 ---------------------------------------------------------------------------*/2172 2173int snd_trident_foldback_pcm(struct snd_trident *trident, int device)2174{2175 struct snd_pcm *foldback;2176 int err;2177 int num_chan = 3;2178 struct snd_pcm_substream *substream;2179 2180 if (trident->device == TRIDENT_DEVICE_ID_NX)2181 num_chan = 4;2182 err = snd_pcm_new(trident->card, "trident_dx_nx", device, 0, num_chan, &foldback);2183 if (err < 0)2184 return err;2185 2186 foldback->private_data = trident;2187 if (trident->tlb.entries)2188 snd_pcm_set_ops(foldback, SNDRV_PCM_STREAM_CAPTURE, &snd_trident_nx_foldback_ops);2189 else2190 snd_pcm_set_ops(foldback, SNDRV_PCM_STREAM_CAPTURE, &snd_trident_foldback_ops);2191 foldback->info_flags = 0;2192 strcpy(foldback->name, "Trident 4DWave");2193 substream = foldback->streams[SNDRV_PCM_STREAM_CAPTURE].substream;2194 strcpy(substream->name, "Front Mixer");2195 substream = substream->next;2196 strcpy(substream->name, "Reverb Mixer");2197 substream = substream->next;2198 strcpy(substream->name, "Chorus Mixer");2199 if (num_chan == 4) {2200 substream = substream->next;2201 strcpy(substream->name, "Second AC'97 ADC");2202 }2203 trident->foldback = foldback;2204 2205 if (trident->tlb.entries)2206 snd_pcm_set_managed_buffer_all(foldback, SNDRV_DMA_TYPE_DEV_SG,2207 &trident->pci->dev,2208 0, 128*1024);2209 else2210 snd_pcm_set_managed_buffer_all(foldback, SNDRV_DMA_TYPE_DEV,2211 &trident->pci->dev,2212 64*1024, 128*1024);2213 2214 return 0;2215}2216 2217/*---------------------------------------------------------------------------2218 snd_trident_spdif2219 2220 Description: This routine registers the 4DWave-NX device for SPDIF support.2221 2222 Parameters: trident - pointer to target device class for 4DWave-NX.2223 2224 Returns: None2225 2226 ---------------------------------------------------------------------------*/2227 2228int snd_trident_spdif_pcm(struct snd_trident *trident, int device)2229{2230 struct snd_pcm *spdif;2231 int err;2232 2233 err = snd_pcm_new(trident->card, "trident_dx_nx IEC958", device, 1, 0, &spdif);2234 if (err < 0)2235 return err;2236 2237 spdif->private_data = trident;2238 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {2239 snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_ops);2240 } else {2241 snd_pcm_set_ops(spdif, SNDRV_PCM_STREAM_PLAYBACK, &snd_trident_spdif_7018_ops);2242 }2243 spdif->info_flags = 0;2244 strcpy(spdif->name, "Trident 4DWave IEC958");2245 trident->spdif = spdif;2246 2247 snd_pcm_set_managed_buffer_all(spdif, SNDRV_DMA_TYPE_DEV,2248 &trident->pci->dev, 64*1024, 128*1024);2249 2250 return 0;2251}2252 2253/*2254 * Mixer part2255 */2256 2257 2258/*---------------------------------------------------------------------------2259 snd_trident_spdif_control2260 2261 Description: enable/disable S/PDIF out from ac97 mixer2262 ---------------------------------------------------------------------------*/2263 2264#define snd_trident_spdif_control_info snd_ctl_boolean_mono_info2265 2266static int snd_trident_spdif_control_get(struct snd_kcontrol *kcontrol,2267 struct snd_ctl_elem_value *ucontrol)2268{2269 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2270 unsigned char val;2271 2272 spin_lock_irq(&trident->reg_lock);2273 val = trident->spdif_ctrl;2274 ucontrol->value.integer.value[0] = val == kcontrol->private_value;2275 spin_unlock_irq(&trident->reg_lock);2276 return 0;2277}2278 2279static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol,2280 struct snd_ctl_elem_value *ucontrol)2281{2282 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2283 unsigned char val;2284 int change;2285 2286 val = ucontrol->value.integer.value[0] ? (unsigned char) kcontrol->private_value : 0x00;2287 spin_lock_irq(&trident->reg_lock);2288 /* S/PDIF C Channel bits 0-31 : 48khz, SCMS disabled */2289 change = trident->spdif_ctrl != val;2290 trident->spdif_ctrl = val;2291 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {2292 if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0) {2293 outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));2294 outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));2295 }2296 } else {2297 if (trident->spdif == NULL) {2298 unsigned int temp;2299 outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));2300 temp = inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & ~SPDIF_EN;2301 if (val)2302 temp |= SPDIF_EN;2303 outl(temp, TRID_REG(trident, SI_SERIAL_INTF_CTRL));2304 }2305 }2306 spin_unlock_irq(&trident->reg_lock);2307 return change;2308}2309 2310static const struct snd_kcontrol_new snd_trident_spdif_control =2311{2312 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2313 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH),2314 .info = snd_trident_spdif_control_info,2315 .get = snd_trident_spdif_control_get,2316 .put = snd_trident_spdif_control_put,2317 .private_value = 0x28,2318};2319 2320/*---------------------------------------------------------------------------2321 snd_trident_spdif_default2322 2323 Description: put/get the S/PDIF default settings2324 ---------------------------------------------------------------------------*/2325 2326static int snd_trident_spdif_default_info(struct snd_kcontrol *kcontrol,2327 struct snd_ctl_elem_info *uinfo)2328{2329 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;2330 uinfo->count = 1;2331 return 0;2332}2333 2334static int snd_trident_spdif_default_get(struct snd_kcontrol *kcontrol,2335 struct snd_ctl_elem_value *ucontrol)2336{2337 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2338 2339 spin_lock_irq(&trident->reg_lock);2340 ucontrol->value.iec958.status[0] = (trident->spdif_bits >> 0) & 0xff;2341 ucontrol->value.iec958.status[1] = (trident->spdif_bits >> 8) & 0xff;2342 ucontrol->value.iec958.status[2] = (trident->spdif_bits >> 16) & 0xff;2343 ucontrol->value.iec958.status[3] = (trident->spdif_bits >> 24) & 0xff;2344 spin_unlock_irq(&trident->reg_lock);2345 return 0;2346}2347 2348static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol,2349 struct snd_ctl_elem_value *ucontrol)2350{2351 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2352 unsigned int val;2353 int change;2354 2355 val = (ucontrol->value.iec958.status[0] << 0) |2356 (ucontrol->value.iec958.status[1] << 8) |2357 (ucontrol->value.iec958.status[2] << 16) |2358 (ucontrol->value.iec958.status[3] << 24);2359 spin_lock_irq(&trident->reg_lock);2360 change = trident->spdif_bits != val;2361 trident->spdif_bits = val;2362 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {2363 if ((inb(TRID_REG(trident, NX_SPCTRL_SPCSO + 3)) & 0x10) == 0)2364 outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));2365 } else {2366 if (trident->spdif == NULL)2367 outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));2368 }2369 spin_unlock_irq(&trident->reg_lock);2370 return change;2371}2372 2373static const struct snd_kcontrol_new snd_trident_spdif_default =2374{2375 .iface = SNDRV_CTL_ELEM_IFACE_PCM,2376 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),2377 .info = snd_trident_spdif_default_info,2378 .get = snd_trident_spdif_default_get,2379 .put = snd_trident_spdif_default_put2380};2381 2382/*---------------------------------------------------------------------------2383 snd_trident_spdif_mask2384 2385 Description: put/get the S/PDIF mask2386 ---------------------------------------------------------------------------*/2387 2388static int snd_trident_spdif_mask_info(struct snd_kcontrol *kcontrol,2389 struct snd_ctl_elem_info *uinfo)2390{2391 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;2392 uinfo->count = 1;2393 return 0;2394}2395 2396static int snd_trident_spdif_mask_get(struct snd_kcontrol *kcontrol,2397 struct snd_ctl_elem_value *ucontrol)2398{2399 ucontrol->value.iec958.status[0] = 0xff;2400 ucontrol->value.iec958.status[1] = 0xff;2401 ucontrol->value.iec958.status[2] = 0xff;2402 ucontrol->value.iec958.status[3] = 0xff;2403 return 0;2404}2405 2406static const struct snd_kcontrol_new snd_trident_spdif_mask =2407{2408 .access = SNDRV_CTL_ELEM_ACCESS_READ,2409 .iface = SNDRV_CTL_ELEM_IFACE_PCM,2410 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),2411 .info = snd_trident_spdif_mask_info,2412 .get = snd_trident_spdif_mask_get,2413};2414 2415/*---------------------------------------------------------------------------2416 snd_trident_spdif_stream2417 2418 Description: put/get the S/PDIF stream settings2419 ---------------------------------------------------------------------------*/2420 2421static int snd_trident_spdif_stream_info(struct snd_kcontrol *kcontrol,2422 struct snd_ctl_elem_info *uinfo)2423{2424 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;2425 uinfo->count = 1;2426 return 0;2427}2428 2429static int snd_trident_spdif_stream_get(struct snd_kcontrol *kcontrol,2430 struct snd_ctl_elem_value *ucontrol)2431{2432 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2433 2434 spin_lock_irq(&trident->reg_lock);2435 ucontrol->value.iec958.status[0] = (trident->spdif_pcm_bits >> 0) & 0xff;2436 ucontrol->value.iec958.status[1] = (trident->spdif_pcm_bits >> 8) & 0xff;2437 ucontrol->value.iec958.status[2] = (trident->spdif_pcm_bits >> 16) & 0xff;2438 ucontrol->value.iec958.status[3] = (trident->spdif_pcm_bits >> 24) & 0xff;2439 spin_unlock_irq(&trident->reg_lock);2440 return 0;2441}2442 2443static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol,2444 struct snd_ctl_elem_value *ucontrol)2445{2446 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2447 unsigned int val;2448 int change;2449 2450 val = (ucontrol->value.iec958.status[0] << 0) |2451 (ucontrol->value.iec958.status[1] << 8) |2452 (ucontrol->value.iec958.status[2] << 16) |2453 (ucontrol->value.iec958.status[3] << 24);2454 spin_lock_irq(&trident->reg_lock);2455 change = trident->spdif_pcm_bits != val;2456 trident->spdif_pcm_bits = val;2457 if (trident->spdif != NULL) {2458 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {2459 outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS));2460 } else {2461 outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));2462 }2463 }2464 spin_unlock_irq(&trident->reg_lock);2465 return change;2466}2467 2468static const struct snd_kcontrol_new snd_trident_spdif_stream =2469{2470 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,2471 .iface = SNDRV_CTL_ELEM_IFACE_PCM,2472 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),2473 .info = snd_trident_spdif_stream_info,2474 .get = snd_trident_spdif_stream_get,2475 .put = snd_trident_spdif_stream_put2476};2477 2478/*---------------------------------------------------------------------------2479 snd_trident_ac97_control2480 2481 Description: enable/disable rear path for ac972482 ---------------------------------------------------------------------------*/2483 2484#define snd_trident_ac97_control_info snd_ctl_boolean_mono_info2485 2486static int snd_trident_ac97_control_get(struct snd_kcontrol *kcontrol,2487 struct snd_ctl_elem_value *ucontrol)2488{2489 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2490 unsigned char val;2491 2492 spin_lock_irq(&trident->reg_lock);2493 val = trident->ac97_ctrl = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));2494 ucontrol->value.integer.value[0] = (val & (1 << kcontrol->private_value)) ? 1 : 0;2495 spin_unlock_irq(&trident->reg_lock);2496 return 0;2497}2498 2499static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol,2500 struct snd_ctl_elem_value *ucontrol)2501{2502 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2503 unsigned char val;2504 int change = 0;2505 2506 spin_lock_irq(&trident->reg_lock);2507 val = trident->ac97_ctrl = inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT));2508 val &= ~(1 << kcontrol->private_value);2509 if (ucontrol->value.integer.value[0])2510 val |= 1 << kcontrol->private_value;2511 change = val != trident->ac97_ctrl;2512 trident->ac97_ctrl = val;2513 outl(trident->ac97_ctrl = val, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));2514 spin_unlock_irq(&trident->reg_lock);2515 return change;2516}2517 2518static const struct snd_kcontrol_new snd_trident_ac97_rear_control =2519{2520 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2521 .name = "Rear Path",2522 .info = snd_trident_ac97_control_info,2523 .get = snd_trident_ac97_control_get,2524 .put = snd_trident_ac97_control_put,2525 .private_value = 4,2526};2527 2528/*---------------------------------------------------------------------------2529 snd_trident_vol_control2530 2531 Description: wave & music volume control2532 ---------------------------------------------------------------------------*/2533 2534static int snd_trident_vol_control_info(struct snd_kcontrol *kcontrol,2535 struct snd_ctl_elem_info *uinfo)2536{2537 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2538 uinfo->count = 2;2539 uinfo->value.integer.min = 0;2540 uinfo->value.integer.max = 255;2541 return 0;2542}2543 2544static int snd_trident_vol_control_get(struct snd_kcontrol *kcontrol,2545 struct snd_ctl_elem_value *ucontrol)2546{2547 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2548 unsigned int val;2549 2550 val = trident->musicvol_wavevol;2551 ucontrol->value.integer.value[0] = 255 - ((val >> kcontrol->private_value) & 0xff);2552 ucontrol->value.integer.value[1] = 255 - ((val >> (kcontrol->private_value + 8)) & 0xff);2553 return 0;2554}2555 2556static const DECLARE_TLV_DB_SCALE(db_scale_gvol, -6375, 25, 0);2557 2558static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol,2559 struct snd_ctl_elem_value *ucontrol)2560{2561 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2562 unsigned int val;2563 int change = 0;2564 2565 spin_lock_irq(&trident->reg_lock);2566 val = trident->musicvol_wavevol;2567 val &= ~(0xffff << kcontrol->private_value);2568 val |= ((255 - (ucontrol->value.integer.value[0] & 0xff)) |2569 ((255 - (ucontrol->value.integer.value[1] & 0xff)) << 8)) << kcontrol->private_value;2570 change = val != trident->musicvol_wavevol;2571 outl(trident->musicvol_wavevol = val, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL));2572 spin_unlock_irq(&trident->reg_lock);2573 return change;2574}2575 2576static const struct snd_kcontrol_new snd_trident_vol_music_control =2577{2578 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2579 .name = "Music Playback Volume",2580 .info = snd_trident_vol_control_info,2581 .get = snd_trident_vol_control_get,2582 .put = snd_trident_vol_control_put,2583 .private_value = 16,2584 .tlv = { .p = db_scale_gvol },2585};2586 2587static const struct snd_kcontrol_new snd_trident_vol_wave_control =2588{2589 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2590 .name = "Wave Playback Volume",2591 .info = snd_trident_vol_control_info,2592 .get = snd_trident_vol_control_get,2593 .put = snd_trident_vol_control_put,2594 .private_value = 0,2595 .tlv = { .p = db_scale_gvol },2596};2597 2598/*---------------------------------------------------------------------------2599 snd_trident_pcm_vol_control2600 2601 Description: PCM front volume control2602 ---------------------------------------------------------------------------*/2603 2604static int snd_trident_pcm_vol_control_info(struct snd_kcontrol *kcontrol,2605 struct snd_ctl_elem_info *uinfo)2606{2607 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2608 2609 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2610 uinfo->count = 1;2611 uinfo->value.integer.min = 0;2612 uinfo->value.integer.max = 255;2613 if (trident->device == TRIDENT_DEVICE_ID_SI7018)2614 uinfo->value.integer.max = 1023;2615 return 0;2616}2617 2618static int snd_trident_pcm_vol_control_get(struct snd_kcontrol *kcontrol,2619 struct snd_ctl_elem_value *ucontrol)2620{2621 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2622 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2623 2624 if (trident->device == TRIDENT_DEVICE_ID_SI7018) {2625 ucontrol->value.integer.value[0] = 1023 - mix->vol;2626 } else {2627 ucontrol->value.integer.value[0] = 255 - (mix->vol>>2);2628 }2629 return 0;2630}2631 2632static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol,2633 struct snd_ctl_elem_value *ucontrol)2634{2635 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2636 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2637 unsigned int val;2638 int change = 0;2639 2640 if (trident->device == TRIDENT_DEVICE_ID_SI7018) {2641 val = 1023 - (ucontrol->value.integer.value[0] & 1023);2642 } else {2643 val = (255 - (ucontrol->value.integer.value[0] & 255)) << 2;2644 }2645 spin_lock_irq(&trident->reg_lock);2646 change = val != mix->vol;2647 mix->vol = val;2648 if (mix->voice != NULL)2649 snd_trident_write_vol_reg(trident, mix->voice, val);2650 spin_unlock_irq(&trident->reg_lock);2651 return change;2652}2653 2654static const struct snd_kcontrol_new snd_trident_pcm_vol_control =2655{2656 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2657 .name = "PCM Front Playback Volume",2658 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,2659 .count = 32,2660 .info = snd_trident_pcm_vol_control_info,2661 .get = snd_trident_pcm_vol_control_get,2662 .put = snd_trident_pcm_vol_control_put,2663 /* FIXME: no tlv yet */2664};2665 2666/*---------------------------------------------------------------------------2667 snd_trident_pcm_pan_control2668 2669 Description: PCM front pan control2670 ---------------------------------------------------------------------------*/2671 2672static int snd_trident_pcm_pan_control_info(struct snd_kcontrol *kcontrol,2673 struct snd_ctl_elem_info *uinfo)2674{2675 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2676 uinfo->count = 1;2677 uinfo->value.integer.min = 0;2678 uinfo->value.integer.max = 127;2679 return 0;2680}2681 2682static int snd_trident_pcm_pan_control_get(struct snd_kcontrol *kcontrol,2683 struct snd_ctl_elem_value *ucontrol)2684{2685 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2686 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2687 2688 ucontrol->value.integer.value[0] = mix->pan;2689 if (ucontrol->value.integer.value[0] & 0x40) {2690 ucontrol->value.integer.value[0] = (0x3f - (ucontrol->value.integer.value[0] & 0x3f));2691 } else {2692 ucontrol->value.integer.value[0] |= 0x40;2693 }2694 return 0;2695}2696 2697static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol,2698 struct snd_ctl_elem_value *ucontrol)2699{2700 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2701 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2702 unsigned char val;2703 int change = 0;2704 2705 if (ucontrol->value.integer.value[0] & 0x40)2706 val = ucontrol->value.integer.value[0] & 0x3f;2707 else2708 val = (0x3f - (ucontrol->value.integer.value[0] & 0x3f)) | 0x40;2709 spin_lock_irq(&trident->reg_lock);2710 change = val != mix->pan;2711 mix->pan = val;2712 if (mix->voice != NULL)2713 snd_trident_write_pan_reg(trident, mix->voice, val);2714 spin_unlock_irq(&trident->reg_lock);2715 return change;2716}2717 2718static const struct snd_kcontrol_new snd_trident_pcm_pan_control =2719{2720 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2721 .name = "PCM Pan Playback Control",2722 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,2723 .count = 32,2724 .info = snd_trident_pcm_pan_control_info,2725 .get = snd_trident_pcm_pan_control_get,2726 .put = snd_trident_pcm_pan_control_put,2727};2728 2729/*---------------------------------------------------------------------------2730 snd_trident_pcm_rvol_control2731 2732 Description: PCM reverb volume control2733 ---------------------------------------------------------------------------*/2734 2735static int snd_trident_pcm_rvol_control_info(struct snd_kcontrol *kcontrol,2736 struct snd_ctl_elem_info *uinfo)2737{2738 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2739 uinfo->count = 1;2740 uinfo->value.integer.min = 0;2741 uinfo->value.integer.max = 127;2742 return 0;2743}2744 2745static int snd_trident_pcm_rvol_control_get(struct snd_kcontrol *kcontrol,2746 struct snd_ctl_elem_value *ucontrol)2747{2748 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2749 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2750 2751 ucontrol->value.integer.value[0] = 127 - mix->rvol;2752 return 0;2753}2754 2755static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol,2756 struct snd_ctl_elem_value *ucontrol)2757{2758 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2759 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2760 unsigned short val;2761 int change = 0;2762 2763 val = 0x7f - (ucontrol->value.integer.value[0] & 0x7f);2764 spin_lock_irq(&trident->reg_lock);2765 change = val != mix->rvol;2766 mix->rvol = val;2767 if (mix->voice != NULL)2768 snd_trident_write_rvol_reg(trident, mix->voice, val);2769 spin_unlock_irq(&trident->reg_lock);2770 return change;2771}2772 2773static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1);2774 2775static const struct snd_kcontrol_new snd_trident_pcm_rvol_control =2776{2777 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2778 .name = "PCM Reverb Playback Volume",2779 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,2780 .count = 32,2781 .info = snd_trident_pcm_rvol_control_info,2782 .get = snd_trident_pcm_rvol_control_get,2783 .put = snd_trident_pcm_rvol_control_put,2784 .tlv = { .p = db_scale_crvol },2785};2786 2787/*---------------------------------------------------------------------------2788 snd_trident_pcm_cvol_control2789 2790 Description: PCM chorus volume control2791 ---------------------------------------------------------------------------*/2792 2793static int snd_trident_pcm_cvol_control_info(struct snd_kcontrol *kcontrol,2794 struct snd_ctl_elem_info *uinfo)2795{2796 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;2797 uinfo->count = 1;2798 uinfo->value.integer.min = 0;2799 uinfo->value.integer.max = 127;2800 return 0;2801}2802 2803static int snd_trident_pcm_cvol_control_get(struct snd_kcontrol *kcontrol,2804 struct snd_ctl_elem_value *ucontrol)2805{2806 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2807 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2808 2809 ucontrol->value.integer.value[0] = 127 - mix->cvol;2810 return 0;2811}2812 2813static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol,2814 struct snd_ctl_elem_value *ucontrol)2815{2816 struct snd_trident *trident = snd_kcontrol_chip(kcontrol);2817 struct snd_trident_pcm_mixer *mix = &trident->pcm_mixer[snd_ctl_get_ioffnum(kcontrol, &ucontrol->id)];2818 unsigned short val;2819 int change = 0;2820 2821 val = 0x7f - (ucontrol->value.integer.value[0] & 0x7f);2822 spin_lock_irq(&trident->reg_lock);2823 change = val != mix->cvol;2824 mix->cvol = val;2825 if (mix->voice != NULL)2826 snd_trident_write_cvol_reg(trident, mix->voice, val);2827 spin_unlock_irq(&trident->reg_lock);2828 return change;2829}2830 2831static const struct snd_kcontrol_new snd_trident_pcm_cvol_control =2832{2833 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,2834 .name = "PCM Chorus Playback Volume",2835 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,2836 .count = 32,2837 .info = snd_trident_pcm_cvol_control_info,2838 .get = snd_trident_pcm_cvol_control_get,2839 .put = snd_trident_pcm_cvol_control_put,2840 .tlv = { .p = db_scale_crvol },2841};2842 2843static void snd_trident_notify_pcm_change1(struct snd_card *card,2844 struct snd_kcontrol *kctl,2845 int num, int activate)2846{2847 struct snd_ctl_elem_id id;2848 2849 if (! kctl)2850 return;2851 if (activate)2852 kctl->vd[num].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;2853 else2854 kctl->vd[num].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;2855 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |2856 SNDRV_CTL_EVENT_MASK_INFO,2857 snd_ctl_build_ioff(&id, kctl, num));2858}2859 2860static void snd_trident_notify_pcm_change(struct snd_trident *trident,2861 struct snd_trident_pcm_mixer *tmix,2862 int num, int activate)2863{2864 snd_trident_notify_pcm_change1(trident->card, trident->ctl_vol, num, activate);2865 snd_trident_notify_pcm_change1(trident->card, trident->ctl_pan, num, activate);2866 snd_trident_notify_pcm_change1(trident->card, trident->ctl_rvol, num, activate);2867 snd_trident_notify_pcm_change1(trident->card, trident->ctl_cvol, num, activate);2868}2869 2870static int snd_trident_pcm_mixer_build(struct snd_trident *trident,2871 struct snd_trident_voice *voice,2872 struct snd_pcm_substream *substream)2873{2874 struct snd_trident_pcm_mixer *tmix;2875 2876 if (snd_BUG_ON(!trident || !voice || !substream))2877 return -EINVAL;2878 tmix = &trident->pcm_mixer[substream->number];2879 tmix->voice = voice;2880 tmix->vol = T4D_DEFAULT_PCM_VOL;2881 tmix->pan = T4D_DEFAULT_PCM_PAN;2882 tmix->rvol = T4D_DEFAULT_PCM_RVOL;2883 tmix->cvol = T4D_DEFAULT_PCM_CVOL;2884 snd_trident_notify_pcm_change(trident, tmix, substream->number, 1);2885 return 0;2886}2887 2888static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_trident_voice *voice, struct snd_pcm_substream *substream)2889{2890 struct snd_trident_pcm_mixer *tmix;2891 2892 if (snd_BUG_ON(!trident || !substream))2893 return -EINVAL;2894 tmix = &trident->pcm_mixer[substream->number];2895 tmix->voice = NULL;2896 snd_trident_notify_pcm_change(trident, tmix, substream->number, 0);2897 return 0;2898}2899 2900/*---------------------------------------------------------------------------2901 snd_trident_mixer2902 2903 Description: This routine registers the 4DWave device for mixer support.2904 2905 Parameters: trident - pointer to target device class for 4DWave.2906 2907 Returns: None2908 2909 ---------------------------------------------------------------------------*/2910 2911static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device)2912{2913 struct snd_ac97_template _ac97;2914 struct snd_card *card = trident->card;2915 struct snd_kcontrol *kctl;2916 struct snd_ctl_elem_value *uctl;2917 int idx, err, retries = 2;2918 static const struct snd_ac97_bus_ops ops = {2919 .write = snd_trident_codec_write,2920 .read = snd_trident_codec_read,2921 };2922 2923 uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);2924 if (!uctl)2925 return -ENOMEM;2926 2927 err = snd_ac97_bus(trident->card, 0, &ops, NULL, &trident->ac97_bus);2928 if (err < 0)2929 goto __out;2930 2931 memset(&_ac97, 0, sizeof(_ac97));2932 _ac97.private_data = trident;2933 trident->ac97_detect = 1;2934 2935 __again:2936 err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97);2937 if (err < 0) {2938 if (trident->device == TRIDENT_DEVICE_ID_SI7018) {2939 err = snd_trident_sis_reset(trident);2940 if (err < 0)2941 goto __out;2942 if (retries-- > 0)2943 goto __again;2944 err = -EIO;2945 }2946 goto __out;2947 }2948 2949 /* secondary codec? */2950 if (trident->device == TRIDENT_DEVICE_ID_SI7018 &&2951 (inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0) {2952 _ac97.num = 1;2953 err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec);2954 if (err < 0)2955 dev_err(trident->card->dev,2956 "SI7018: the secondary codec - invalid access\n");2957#if 0 // only for my testing purpose --jk2958 {2959 struct snd_ac97 *mc97;2960 err = snd_ac97_modem(trident->card, &_ac97, &mc97);2961 if (err < 0)2962 dev_err(trident->card->dev,2963 "snd_ac97_modem returned error %i\n", err);2964 }2965#endif2966 }2967 2968 trident->ac97_detect = 0;2969 2970 if (trident->device != TRIDENT_DEVICE_ID_SI7018) {2971 kctl = snd_ctl_new1(&snd_trident_vol_wave_control, trident);2972 err = snd_ctl_add(card, kctl);2973 if (err < 0)2974 goto __out;2975 kctl->put(kctl, uctl);2976 kctl = snd_ctl_new1(&snd_trident_vol_music_control, trident);2977 err = snd_ctl_add(card, kctl);2978 if (err < 0)2979 goto __out;2980 kctl->put(kctl, uctl);2981 outl(trident->musicvol_wavevol = 0x00000000, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL));2982 } else {2983 outl(trident->musicvol_wavevol = 0xffff0000, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL));2984 }2985 2986 for (idx = 0; idx < 32; idx++) {2987 struct snd_trident_pcm_mixer *tmix;2988 2989 tmix = &trident->pcm_mixer[idx];2990 tmix->voice = NULL;2991 }2992 trident->ctl_vol = snd_ctl_new1(&snd_trident_pcm_vol_control, trident);2993 if (!trident->ctl_vol)2994 goto __nomem;2995 err = snd_ctl_add(card, trident->ctl_vol);2996 if (err)2997 goto __out;2998 2999 trident->ctl_pan = snd_ctl_new1(&snd_trident_pcm_pan_control, trident);3000 if (!trident->ctl_pan)3001 goto __nomem;3002 err = snd_ctl_add(card, trident->ctl_pan);3003 if (err)3004 goto __out;3005 3006 trident->ctl_rvol = snd_ctl_new1(&snd_trident_pcm_rvol_control, trident);3007 if (!trident->ctl_rvol)3008 goto __nomem;3009 err = snd_ctl_add(card, trident->ctl_rvol);3010 if (err)3011 goto __out;3012 3013 trident->ctl_cvol = snd_ctl_new1(&snd_trident_pcm_cvol_control, trident);3014 if (!trident->ctl_cvol)3015 goto __nomem;3016 err = snd_ctl_add(card, trident->ctl_cvol);3017 if (err)3018 goto __out;3019 3020 if (trident->device == TRIDENT_DEVICE_ID_NX) {3021 kctl = snd_ctl_new1(&snd_trident_ac97_rear_control, trident);3022 err = snd_ctl_add(card, kctl);3023 if (err < 0)3024 goto __out;3025 kctl->put(kctl, uctl);3026 }3027 if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) {3028 3029 kctl = snd_ctl_new1(&snd_trident_spdif_control, trident);3030 if (kctl == NULL) {3031 err = -ENOMEM;3032 goto __out;3033 }3034 if (trident->ac97->ext_id & AC97_EI_SPDIF)3035 kctl->id.index++;3036 if (trident->ac97_sec && (trident->ac97_sec->ext_id & AC97_EI_SPDIF))3037 kctl->id.index++;3038 idx = kctl->id.index;3039 err = snd_ctl_add(card, kctl);3040 if (err < 0)3041 goto __out;3042 kctl->put(kctl, uctl);3043 3044 kctl = snd_ctl_new1(&snd_trident_spdif_default, trident);3045 if (kctl == NULL) {3046 err = -ENOMEM;3047 goto __out;3048 }3049 kctl->id.index = idx;3050 kctl->id.device = pcm_spdif_device;3051 err = snd_ctl_add(card, kctl);3052 if (err < 0)3053 goto __out;3054 3055 kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident);3056 if (kctl == NULL) {3057 err = -ENOMEM;3058 goto __out;3059 }3060 kctl->id.index = idx;3061 kctl->id.device = pcm_spdif_device;3062 err = snd_ctl_add(card, kctl);3063 if (err < 0)3064 goto __out;3065 3066 kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident);3067 if (kctl == NULL) {3068 err = -ENOMEM;3069 goto __out;3070 }3071 kctl->id.index = idx;3072 kctl->id.device = pcm_spdif_device;3073 err = snd_ctl_add(card, kctl);3074 if (err < 0)3075 goto __out;3076 trident->spdif_pcm_ctl = kctl;3077 }3078 3079 err = 0;3080 goto __out;3081 3082 __nomem:3083 err = -ENOMEM;3084 3085 __out:3086 kfree(uctl);3087 3088 return err;3089}3090 3091/*3092 * gameport interface3093 */3094 3095#if IS_REACHABLE(CONFIG_GAMEPORT)3096 3097static unsigned char snd_trident_gameport_read(struct gameport *gameport)3098{3099 struct snd_trident *chip = gameport_get_port_data(gameport);3100 3101 if (snd_BUG_ON(!chip))3102 return 0;3103 return inb(TRID_REG(chip, GAMEPORT_LEGACY));3104}3105 3106static void snd_trident_gameport_trigger(struct gameport *gameport)3107{3108 struct snd_trident *chip = gameport_get_port_data(gameport);3109 3110 if (snd_BUG_ON(!chip))3111 return;3112 outb(0xff, TRID_REG(chip, GAMEPORT_LEGACY));3113}3114 3115static int snd_trident_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)3116{3117 struct snd_trident *chip = gameport_get_port_data(gameport);3118 int i;3119 3120 if (snd_BUG_ON(!chip))3121 return 0;3122 3123 *buttons = (~inb(TRID_REG(chip, GAMEPORT_LEGACY)) >> 4) & 0xf;3124 3125 for (i = 0; i < 4; i++) {3126 axes[i] = inw(TRID_REG(chip, GAMEPORT_AXES + i * 2));3127 if (axes[i] == 0xffff) axes[i] = -1;3128 }3129 3130 return 0;3131}3132 3133static int snd_trident_gameport_open(struct gameport *gameport, int mode)3134{3135 struct snd_trident *chip = gameport_get_port_data(gameport);3136 3137 if (snd_BUG_ON(!chip))3138 return 0;3139 3140 switch (mode) {3141 case GAMEPORT_MODE_COOKED:3142 outb(GAMEPORT_MODE_ADC, TRID_REG(chip, GAMEPORT_GCR));3143 msleep(20);3144 return 0;3145 case GAMEPORT_MODE_RAW:3146 outb(0, TRID_REG(chip, GAMEPORT_GCR));3147 return 0;3148 default:3149 return -1;3150 }3151}3152 3153int snd_trident_create_gameport(struct snd_trident *chip)3154{3155 struct gameport *gp;3156 3157 chip->gameport = gp = gameport_allocate_port();3158 if (!gp) {3159 dev_err(chip->card->dev,3160 "cannot allocate memory for gameport\n");3161 return -ENOMEM;3162 }3163 3164 gameport_set_name(gp, "Trident 4DWave");3165 gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci));3166 gameport_set_dev_parent(gp, &chip->pci->dev);3167 3168 gameport_set_port_data(gp, chip);3169 gp->fuzz = 64;3170 gp->read = snd_trident_gameport_read;3171 gp->trigger = snd_trident_gameport_trigger;3172 gp->cooked_read = snd_trident_gameport_cooked_read;3173 gp->open = snd_trident_gameport_open;3174 3175 gameport_register_port(gp);3176 3177 return 0;3178}3179 3180static inline void snd_trident_free_gameport(struct snd_trident *chip)3181{3182 if (chip->gameport) {3183 gameport_unregister_port(chip->gameport);3184 chip->gameport = NULL;3185 }3186}3187#else3188int snd_trident_create_gameport(struct snd_trident *chip) { return -ENOSYS; }3189static inline void snd_trident_free_gameport(struct snd_trident *chip) { }3190#endif /* CONFIG_GAMEPORT */3191 3192/*3193 * delay for 1 tick3194 */3195static inline void do_delay(struct snd_trident *chip)3196{3197 schedule_timeout_uninterruptible(1);3198}3199 3200/*3201 * SiS reset routine3202 */3203 3204static int snd_trident_sis_reset(struct snd_trident *trident)3205{3206 unsigned long end_time;3207 unsigned int i;3208 int r;3209 3210 r = trident->in_suspend ? 0 : 2; /* count of retries */3211 __si7018_retry:3212 pci_write_config_byte(trident->pci, 0x46, 0x04); /* SOFTWARE RESET */3213 udelay(100);3214 pci_write_config_byte(trident->pci, 0x46, 0x00);3215 udelay(100);3216 /* disable AC97 GPIO interrupt */3217 outb(0x00, TRID_REG(trident, SI_AC97_GPIO));3218 /* initialize serial interface, force cold reset */3219 i = PCMOUT|SURROUT|CENTEROUT|LFEOUT|SECONDARY_ID|COLD_RESET;3220 outl(i, TRID_REG(trident, SI_SERIAL_INTF_CTRL));3221 udelay(1000);3222 /* remove cold reset */3223 i &= ~COLD_RESET;3224 outl(i, TRID_REG(trident, SI_SERIAL_INTF_CTRL));3225 udelay(2000);3226 /* wait, until the codec is ready */3227 end_time = (jiffies + (HZ * 3) / 4) + 1;3228 do {3229 if ((inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0)3230 goto __si7018_ok;3231 do_delay(trident);3232 } while (time_after_eq(end_time, jiffies));3233 dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n",3234 inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)));3235 if (r-- > 0) {3236 end_time = jiffies + HZ;3237 do {3238 do_delay(trident);3239 } while (time_after_eq(end_time, jiffies));3240 goto __si7018_retry;3241 }3242 __si7018_ok:3243 /* wait for the second codec */3244 do {3245 if ((inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_SECONDARY_READY) != 0)3246 break;3247 do_delay(trident);3248 } while (time_after_eq(end_time, jiffies));3249 /* enable 64 channel mode */3250 outl(BANK_B_EN, TRID_REG(trident, T4D_LFO_GC_CIR));3251 return 0;3252}3253 3254/* 3255 * /proc interface3256 */3257 3258static void snd_trident_proc_read(struct snd_info_entry *entry, 3259 struct snd_info_buffer *buffer)3260{3261 struct snd_trident *trident = entry->private_data;3262 char *s;3263 3264 switch (trident->device) {3265 case TRIDENT_DEVICE_ID_SI7018:3266 s = "SiS 7018 Audio";3267 break;3268 case TRIDENT_DEVICE_ID_DX:3269 s = "Trident 4DWave PCI DX";3270 break;3271 case TRIDENT_DEVICE_ID_NX:3272 s = "Trident 4DWave PCI NX";3273 break;3274 default:3275 s = "???";3276 }3277 snd_iprintf(buffer, "%s\n\n", s);3278 snd_iprintf(buffer, "Spurious IRQs : %d\n", trident->spurious_irq_count);3279 snd_iprintf(buffer, "Spurious IRQ dlta: %d\n", trident->spurious_irq_max_delta);3280 if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018)3281 snd_iprintf(buffer, "IEC958 Mixer Out : %s\n", trident->spdif_ctrl == 0x28 ? "on" : "off");3282 if (trident->device == TRIDENT_DEVICE_ID_NX) {3283 snd_iprintf(buffer, "Rear Speakers : %s\n", trident->ac97_ctrl & 0x00000010 ? "on" : "off");3284 if (trident->tlb.entries) {3285 snd_iprintf(buffer,"\nVirtual Memory\n");3286 snd_iprintf(buffer, "Memory Maximum : %d\n", trident->tlb.memhdr->size);3287 snd_iprintf(buffer, "Memory Used : %d\n", trident->tlb.memhdr->used);3288 snd_iprintf(buffer, "Memory Free : %d\n", snd_util_mem_avail(trident->tlb.memhdr));3289 }3290 }3291}3292 3293static void snd_trident_proc_init(struct snd_trident *trident)3294{3295 const char *s = "trident";3296 3297 if (trident->device == TRIDENT_DEVICE_ID_SI7018)3298 s = "sis7018";3299 snd_card_ro_proc_new(trident->card, s, trident, snd_trident_proc_read);3300}3301 3302/*---------------------------------------------------------------------------3303 snd_trident_tlb_alloc3304 3305 Description: Allocate and set up the TLB page table on 4D NX.3306 Each entry has 4 bytes (physical PCI address).3307 3308 Parameters: trident - pointer to target device class for 4DWave.3309 3310 Returns: 0 or negative error code3311 3312 ---------------------------------------------------------------------------*/3313 3314static int snd_trident_tlb_alloc(struct snd_trident *trident)3315{3316 int i;3317 3318 /* TLB array must be aligned to 16kB !!! so we allocate3319 32kB region and correct offset when necessary */3320 3321 trident->tlb.buffer =3322 snd_devm_alloc_pages(&trident->pci->dev, SNDRV_DMA_TYPE_DEV,3323 2 * SNDRV_TRIDENT_MAX_PAGES * 4);3324 if (!trident->tlb.buffer) {3325 dev_err(trident->card->dev, "unable to allocate TLB buffer\n");3326 return -ENOMEM;3327 }3328 trident->tlb.entries = (__le32 *)ALIGN((unsigned long)trident->tlb.buffer->area, SNDRV_TRIDENT_MAX_PAGES * 4);3329 trident->tlb.entries_dmaaddr = ALIGN(trident->tlb.buffer->addr, SNDRV_TRIDENT_MAX_PAGES * 4);3330 3331 /* allocate and setup silent page and initialise TLB entries */3332 trident->tlb.silent_page =3333 snd_devm_alloc_pages(&trident->pci->dev, SNDRV_DMA_TYPE_DEV,3334 SNDRV_TRIDENT_PAGE_SIZE);3335 if (!trident->tlb.silent_page) {3336 dev_err(trident->card->dev, "unable to allocate silent page\n");3337 return -ENOMEM;3338 }3339 memset(trident->tlb.silent_page->area, 0, SNDRV_TRIDENT_PAGE_SIZE);3340 for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++)3341 trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page->addr & ~(SNDRV_TRIDENT_PAGE_SIZE-1));3342 3343 /* use emu memory block manager code to manage tlb page allocation */3344 trident->tlb.memhdr = snd_util_memhdr_new(SNDRV_TRIDENT_PAGE_SIZE * SNDRV_TRIDENT_MAX_PAGES);3345 if (trident->tlb.memhdr == NULL)3346 return -ENOMEM;3347 3348 trident->tlb.memhdr->block_extra_size = sizeof(struct snd_trident_memblk_arg);3349 return 0;3350}3351 3352/*3353 * initialize 4D DX chip3354 */3355 3356static void snd_trident_stop_all_voices(struct snd_trident *trident)3357{3358 outl(0xffffffff, TRID_REG(trident, T4D_STOP_A));3359 outl(0xffffffff, TRID_REG(trident, T4D_STOP_B));3360 outl(0, TRID_REG(trident, T4D_AINTEN_A));3361 outl(0, TRID_REG(trident, T4D_AINTEN_B));3362}3363 3364static int snd_trident_4d_dx_init(struct snd_trident *trident)3365{3366 struct pci_dev *pci = trident->pci;3367 unsigned long end_time;3368 3369 /* reset the legacy configuration and whole audio/wavetable block */3370 pci_write_config_dword(pci, 0x40, 0); /* DDMA */3371 pci_write_config_byte(pci, 0x44, 0); /* ports */3372 pci_write_config_byte(pci, 0x45, 0); /* Legacy DMA */3373 pci_write_config_byte(pci, 0x46, 4); /* reset */3374 udelay(100);3375 pci_write_config_byte(pci, 0x46, 0); /* release reset */3376 udelay(100);3377 3378 /* warm reset of the AC'97 codec */3379 outl(0x00000001, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));3380 udelay(100);3381 outl(0x00000000, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));3382 /* DAC on, disable SB IRQ and try to force ADC valid signal */3383 trident->ac97_ctrl = 0x0000004a;3384 outl(trident->ac97_ctrl, TRID_REG(trident, DX_ACR2_AC97_COM_STAT));3385 /* wait, until the codec is ready */3386 end_time = (jiffies + (HZ * 3) / 4) + 1;3387 do {3388 if ((inl(TRID_REG(trident, DX_ACR2_AC97_COM_STAT)) & 0x0010) != 0)3389 goto __dx_ok;3390 do_delay(trident);3391 } while (time_after_eq(end_time, jiffies));3392 dev_err(trident->card->dev, "AC'97 codec ready error\n");3393 return -EIO;3394 3395 __dx_ok:3396 snd_trident_stop_all_voices(trident);3397 3398 return 0;3399}3400 3401/*3402 * initialize 4D NX chip3403 */3404static int snd_trident_4d_nx_init(struct snd_trident *trident)3405{3406 struct pci_dev *pci = trident->pci;3407 unsigned long end_time;3408 3409 /* reset the legacy configuration and whole audio/wavetable block */3410 pci_write_config_dword(pci, 0x40, 0); /* DDMA */3411 pci_write_config_byte(pci, 0x44, 0); /* ports */3412 pci_write_config_byte(pci, 0x45, 0); /* Legacy DMA */3413 3414 pci_write_config_byte(pci, 0x46, 1); /* reset */3415 udelay(100);3416 pci_write_config_byte(pci, 0x46, 0); /* release reset */3417 udelay(100);3418 3419 /* warm reset of the AC'97 codec */3420 outl(0x00000001, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));3421 udelay(100);3422 outl(0x00000000, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));3423 /* wait, until the codec is ready */3424 end_time = (jiffies + (HZ * 3) / 4) + 1;3425 do {3426 if ((inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)) & 0x0008) != 0)3427 goto __nx_ok;3428 do_delay(trident);3429 } while (time_after_eq(end_time, jiffies));3430 dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n",3431 inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT)));3432 return -EIO;3433 3434 __nx_ok:3435 /* DAC on */3436 trident->ac97_ctrl = 0x00000002;3437 outl(trident->ac97_ctrl, TRID_REG(trident, NX_ACR0_AC97_COM_STAT));3438 /* disable SB IRQ */3439 outl(NX_SB_IRQ_DISABLE, TRID_REG(trident, T4D_MISCINT));3440 3441 snd_trident_stop_all_voices(trident);3442 3443 if (trident->tlb.entries != NULL) {3444 unsigned int i;3445 /* enable virtual addressing via TLB */3446 i = trident->tlb.entries_dmaaddr;3447 i |= 0x00000001;3448 outl(i, TRID_REG(trident, NX_TLBC));3449 } else {3450 outl(0, TRID_REG(trident, NX_TLBC));3451 }3452 /* initialize S/PDIF */3453 outl(trident->spdif_bits, TRID_REG(trident, NX_SPCSTATUS));3454 outb(trident->spdif_ctrl, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));3455 3456 return 0;3457}3458 3459/*3460 * initialize sis7018 chip3461 */3462static int snd_trident_sis_init(struct snd_trident *trident)3463{3464 int err;3465 3466 err = snd_trident_sis_reset(trident);3467 if (err < 0)3468 return err;3469 3470 snd_trident_stop_all_voices(trident);3471 3472 /* initialize S/PDIF */3473 outl(trident->spdif_bits, TRID_REG(trident, SI_SPDIF_CS));3474 3475 return 0;3476}3477 3478/*---------------------------------------------------------------------------3479 snd_trident_create3480 3481 Description: This routine will create the device specific class for3482 the 4DWave card. It will also perform basic initialization.3483 3484 Parameters: card - which card to create3485 pci - interface to PCI bus resource info3486 dma1ptr - playback dma buffer3487 dma2ptr - capture dma buffer3488 irqptr - interrupt resource info3489 3490 Returns: 4DWave device class private data3491 3492 ---------------------------------------------------------------------------*/3493 3494int snd_trident_create(struct snd_card *card,3495 struct pci_dev *pci,3496 int pcm_streams,3497 int pcm_spdif_device,3498 int max_wavetable_size)3499{3500 struct snd_trident *trident = card->private_data;3501 int i, err;3502 struct snd_trident_voice *voice;3503 struct snd_trident_pcm_mixer *tmix;3504 3505 /* enable PCI device */3506 err = pcim_enable_device(pci);3507 if (err < 0)3508 return err;3509 /* check, if we can restrict PCI DMA transfers to 30 bits */3510 if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(30))) {3511 dev_err(card->dev,3512 "architecture does not support 30bit PCI busmaster DMA\n");3513 return -ENXIO;3514 }3515 3516 trident->device = (pci->vendor << 16) | pci->device;3517 trident->card = card;3518 trident->pci = pci;3519 spin_lock_init(&trident->reg_lock);3520 spin_lock_init(&trident->event_lock);3521 spin_lock_init(&trident->voice_alloc);3522 if (pcm_streams < 1)3523 pcm_streams = 1;3524 if (pcm_streams > 32)3525 pcm_streams = 32;3526 trident->ChanPCM = pcm_streams;3527 if (max_wavetable_size < 0 )3528 max_wavetable_size = 0;3529 trident->synth.max_size = max_wavetable_size * 1024;3530 trident->irq = -1;3531 card->private_free = snd_trident_free;3532 3533 trident->midi_port = TRID_REG(trident, T4D_MPU401_BASE);3534 pci_set_master(pci);3535 3536 err = pci_request_regions(pci, "Trident Audio");3537 if (err < 0)3538 return err;3539 trident->port = pci_resource_start(pci, 0);3540 3541 if (devm_request_irq(&pci->dev, pci->irq, snd_trident_interrupt,3542 IRQF_SHARED, KBUILD_MODNAME, trident)) {3543 dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);3544 return -EBUSY;3545 }3546 trident->irq = pci->irq;3547 card->sync_irq = trident->irq;3548 3549 /* allocate 16k-aligned TLB for NX cards */3550 trident->tlb.entries = NULL;3551 if (trident->device == TRIDENT_DEVICE_ID_NX) {3552 err = snd_trident_tlb_alloc(trident);3553 if (err < 0)3554 return err;3555 }3556 3557 trident->spdif_bits = trident->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;3558 3559 /* initialize chip */3560 switch (trident->device) {3561 case TRIDENT_DEVICE_ID_DX:3562 err = snd_trident_4d_dx_init(trident);3563 break;3564 case TRIDENT_DEVICE_ID_NX:3565 err = snd_trident_4d_nx_init(trident);3566 break;3567 case TRIDENT_DEVICE_ID_SI7018:3568 err = snd_trident_sis_init(trident);3569 break;3570 default:3571 snd_BUG();3572 break;3573 }3574 if (err < 0)3575 return err;3576 3577 err = snd_trident_mixer(trident, pcm_spdif_device);3578 if (err < 0)3579 return err;3580 3581 /* initialise synth voices */3582 for (i = 0; i < 64; i++) {3583 voice = &trident->synth.voices[i];3584 voice->number = i;3585 voice->trident = trident;3586 }3587 /* initialize pcm mixer entries */3588 for (i = 0; i < 32; i++) {3589 tmix = &trident->pcm_mixer[i];3590 tmix->vol = T4D_DEFAULT_PCM_VOL;3591 tmix->pan = T4D_DEFAULT_PCM_PAN;3592 tmix->rvol = T4D_DEFAULT_PCM_RVOL;3593 tmix->cvol = T4D_DEFAULT_PCM_CVOL;3594 }3595 3596 snd_trident_enable_eso(trident);3597 3598 snd_trident_proc_init(trident);3599 return 0;3600}3601 3602/*---------------------------------------------------------------------------3603 snd_trident_free3604 3605 Description: This routine will free the device specific class for3606 the 4DWave card. 3607 3608 Parameters: card - card to release3609 3610 Returns: None.3611 3612 ---------------------------------------------------------------------------*/3613 3614static void snd_trident_free(struct snd_card *card)3615{3616 struct snd_trident *trident = card->private_data;3617 3618 snd_trident_free_gameport(trident);3619 snd_trident_disable_eso(trident);3620 // Disable S/PDIF out3621 if (trident->device == TRIDENT_DEVICE_ID_NX)3622 outb(0x00, TRID_REG(trident, NX_SPCTRL_SPCSO + 3));3623 else if (trident->device == TRIDENT_DEVICE_ID_SI7018) {3624 outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL));3625 }3626 if (trident->tlb.buffer) {3627 outl(0, TRID_REG(trident, NX_TLBC));3628 snd_util_memhdr_free(trident->tlb.memhdr);3629 }3630}3631 3632/*---------------------------------------------------------------------------3633 snd_trident_interrupt3634 3635 Description: ISR for Trident 4DWave device3636 3637 Parameters: trident - device specific private data for 4DWave card3638 3639 Problems: It seems that Trident chips generates interrupts more than3640 one time in special cases. The spurious interrupts are3641 detected via sample timer (T4D_STIMER) and computing3642 corresponding delta value. The limits are detected with3643 the method try & fail so it is possible that it won't3644 work on all computers. [jaroslav]3645 3646 Returns: None.3647 3648 ---------------------------------------------------------------------------*/3649 3650static irqreturn_t snd_trident_interrupt(int irq, void *dev_id)3651{3652 struct snd_trident *trident = dev_id;3653 unsigned int audio_int, chn_int, stimer, channel, mask, tmp;3654 int delta;3655 struct snd_trident_voice *voice;3656 3657 audio_int = inl(TRID_REG(trident, T4D_MISCINT));3658 if ((audio_int & (ADDRESS_IRQ|MPU401_IRQ)) == 0)3659 return IRQ_NONE;3660 if (audio_int & ADDRESS_IRQ) {3661 // get interrupt status for all channels3662 spin_lock(&trident->reg_lock);3663 stimer = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff;3664 chn_int = inl(TRID_REG(trident, T4D_AINT_A));3665 if (chn_int == 0)3666 goto __skip1;3667 outl(chn_int, TRID_REG(trident, T4D_AINT_A)); /* ack */3668 __skip1:3669 chn_int = inl(TRID_REG(trident, T4D_AINT_B));3670 if (chn_int == 0)3671 goto __skip2;3672 for (channel = 63; channel >= 32; channel--) {3673 mask = 1 << (channel&0x1f);3674 if ((chn_int & mask) == 0)3675 continue;3676 voice = &trident->synth.voices[channel];3677 if (!voice->pcm || voice->substream == NULL) {3678 outl(mask, TRID_REG(trident, T4D_STOP_B));3679 continue;3680 }3681 delta = (int)stimer - (int)voice->stimer;3682 if (delta < 0)3683 delta = -delta;3684 if ((unsigned int)delta < voice->spurious_threshold) {3685 /* do some statistics here */3686 trident->spurious_irq_count++;3687 if (trident->spurious_irq_max_delta < (unsigned int)delta)3688 trident->spurious_irq_max_delta = delta;3689 continue;3690 }3691 voice->stimer = stimer;3692 if (voice->isync) {3693 if (!voice->isync3) {3694 tmp = inw(TRID_REG(trident, T4D_SBBL_SBCL));3695 if (trident->bDMAStart & 0x40)3696 tmp >>= 1;3697 if (tmp > 0)3698 tmp = voice->isync_max - tmp;3699 } else {3700 tmp = inl(TRID_REG(trident, NX_SPCTRL_SPCSO)) & 0x00ffffff;3701 }3702 if (tmp < voice->isync_mark) {3703 if (tmp > 0x10)3704 tmp = voice->isync_ESO - 7;3705 else3706 tmp = voice->isync_ESO + 2;3707 /* update ESO for IRQ voice to preserve sync */3708 snd_trident_stop_voice(trident, voice->number);3709 snd_trident_write_eso_reg(trident, voice, tmp);3710 snd_trident_start_voice(trident, voice->number);3711 }3712 } else if (voice->isync2) {3713 voice->isync2 = 0;3714 /* write original ESO and update CSO for IRQ voice to preserve sync */3715 snd_trident_stop_voice(trident, voice->number);3716 snd_trident_write_cso_reg(trident, voice, voice->isync_mark);3717 snd_trident_write_eso_reg(trident, voice, voice->ESO);3718 snd_trident_start_voice(trident, voice->number);3719 }3720#if 03721 if (voice->extra) {3722 /* update CSO for extra voice to preserve sync */3723 snd_trident_stop_voice(trident, voice->extra->number);3724 snd_trident_write_cso_reg(trident, voice->extra, 0);3725 snd_trident_start_voice(trident, voice->extra->number);3726 }3727#endif3728 spin_unlock(&trident->reg_lock);3729 snd_pcm_period_elapsed(voice->substream);3730 spin_lock(&trident->reg_lock);3731 }3732 outl(chn_int, TRID_REG(trident, T4D_AINT_B)); /* ack */3733 __skip2:3734 spin_unlock(&trident->reg_lock);3735 }3736 if (audio_int & MPU401_IRQ) {3737 if (trident->rmidi) {3738 snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data);3739 } else {3740 inb(TRID_REG(trident, T4D_MPUR0));3741 }3742 }3743 // outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(trident, T4D_MISCINT));3744 return IRQ_HANDLED;3745}3746 3747struct snd_trident_voice *snd_trident_alloc_voice(struct snd_trident * trident, int type, int client, int port)3748{3749 struct snd_trident_voice *pvoice;3750 unsigned long flags;3751 int idx;3752 3753 spin_lock_irqsave(&trident->voice_alloc, flags);3754 if (type == SNDRV_TRIDENT_VOICE_TYPE_PCM) {3755 idx = snd_trident_allocate_pcm_channel(trident);3756 if(idx < 0) {3757 spin_unlock_irqrestore(&trident->voice_alloc, flags);3758 return NULL;3759 }3760 pvoice = &trident->synth.voices[idx];3761 pvoice->use = 1;3762 pvoice->pcm = 1;3763 pvoice->capture = 0;3764 pvoice->spdif = 0;3765 pvoice->memblk = NULL;3766 pvoice->substream = NULL;3767 spin_unlock_irqrestore(&trident->voice_alloc, flags);3768 return pvoice;3769 }3770 if (type == SNDRV_TRIDENT_VOICE_TYPE_SYNTH) {3771 idx = snd_trident_allocate_synth_channel(trident);3772 if(idx < 0) {3773 spin_unlock_irqrestore(&trident->voice_alloc, flags);3774 return NULL;3775 }3776 pvoice = &trident->synth.voices[idx];3777 pvoice->use = 1;3778 pvoice->synth = 1;3779 pvoice->client = client;3780 pvoice->port = port;3781 pvoice->memblk = NULL;3782 spin_unlock_irqrestore(&trident->voice_alloc, flags);3783 return pvoice;3784 }3785 if (type == SNDRV_TRIDENT_VOICE_TYPE_MIDI) {3786 }3787 spin_unlock_irqrestore(&trident->voice_alloc, flags);3788 return NULL;3789}3790 3791EXPORT_SYMBOL(snd_trident_alloc_voice);3792 3793void snd_trident_free_voice(struct snd_trident * trident, struct snd_trident_voice *voice)3794{3795 unsigned long flags;3796 void (*private_free)(struct snd_trident_voice *);3797 3798 if (voice == NULL || !voice->use)3799 return;3800 snd_trident_clear_voices(trident, voice->number, voice->number);3801 spin_lock_irqsave(&trident->voice_alloc, flags);3802 private_free = voice->private_free;3803 voice->private_free = NULL;3804 voice->private_data = NULL;3805 if (voice->pcm)3806 snd_trident_free_pcm_channel(trident, voice->number);3807 if (voice->synth)3808 snd_trident_free_synth_channel(trident, voice->number);3809 voice->use = voice->pcm = voice->synth = voice->midi = 0;3810 voice->capture = voice->spdif = 0;3811 voice->sample_ops = NULL;3812 voice->substream = NULL;3813 voice->extra = NULL;3814 spin_unlock_irqrestore(&trident->voice_alloc, flags);3815 if (private_free)3816 private_free(voice);3817}3818 3819EXPORT_SYMBOL(snd_trident_free_voice);3820 3821static void snd_trident_clear_voices(struct snd_trident * trident, unsigned short v_min, unsigned short v_max)3822{3823 unsigned int i, val, mask[2] = { 0, 0 };3824 3825 if (snd_BUG_ON(v_min > 63 || v_max > 63))3826 return;3827 for (i = v_min; i <= v_max; i++)3828 mask[i >> 5] |= 1 << (i & 0x1f);3829 if (mask[0]) {3830 outl(mask[0], TRID_REG(trident, T4D_STOP_A));3831 val = inl(TRID_REG(trident, T4D_AINTEN_A));3832 outl(val & ~mask[0], TRID_REG(trident, T4D_AINTEN_A));3833 }3834 if (mask[1]) {3835 outl(mask[1], TRID_REG(trident, T4D_STOP_B));3836 val = inl(TRID_REG(trident, T4D_AINTEN_B));3837 outl(val & ~mask[1], TRID_REG(trident, T4D_AINTEN_B));3838 }3839}3840 3841#ifdef CONFIG_PM_SLEEP3842static int snd_trident_suspend(struct device *dev)3843{3844 struct snd_card *card = dev_get_drvdata(dev);3845 struct snd_trident *trident = card->private_data;3846 3847 trident->in_suspend = 1;3848 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);3849 snd_ac97_suspend(trident->ac97);3850 snd_ac97_suspend(trident->ac97_sec);3851 return 0;3852}3853 3854static int snd_trident_resume(struct device *dev)3855{3856 struct snd_card *card = dev_get_drvdata(dev);3857 struct snd_trident *trident = card->private_data;3858 3859 switch (trident->device) {3860 case TRIDENT_DEVICE_ID_DX:3861 snd_trident_4d_dx_init(trident);3862 break;3863 case TRIDENT_DEVICE_ID_NX:3864 snd_trident_4d_nx_init(trident);3865 break;3866 case TRIDENT_DEVICE_ID_SI7018:3867 snd_trident_sis_init(trident);3868 break;3869 }3870 3871 snd_ac97_resume(trident->ac97);3872 snd_ac97_resume(trident->ac97_sec);3873 3874 /* restore some registers */3875 outl(trident->musicvol_wavevol, TRID_REG(trident, T4D_MUSICVOL_WAVEVOL));3876 3877 snd_trident_enable_eso(trident);3878 3879 snd_power_change_state(card, SNDRV_CTL_POWER_D0);3880 trident->in_suspend = 0;3881 return 0;3882}3883 3884SIMPLE_DEV_PM_OPS(snd_trident_pm, snd_trident_suspend, snd_trident_resume);3885#endif /* CONFIG_PM_SLEEP */3886