📄 cs46xx.c
字号:
* correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr - * GOF_PER_SEC * correctionPerGOF * initialDelay = ceil((24 * Fs,in) / Fs,out) * * i.e. * * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in)) * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out) * correctionPerGOF:correctionPerSec = * dividend:remainder(ulOther / GOF_PER_SEC) * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out) */ tmp1 = rate << 16; coeffIncr = tmp1 / 48000; tmp1 -= coeffIncr * 48000; tmp1 <<= 7; coeffIncr <<= 7; coeffIncr += tmp1 / 48000; coeffIncr ^= 0xFFFFFFFF; coeffIncr++; tmp1 = 48000 << 16; phiIncr = tmp1 / rate; tmp1 -= phiIncr * rate; tmp1 <<= 10; phiIncr <<= 10; tmp2 = tmp1 / rate; phiIncr += tmp2; tmp1 -= tmp2 * rate; correctionPerGOF = tmp1 / GOF_PER_SEC; tmp1 -= correctionPerGOF * GOF_PER_SEC; correctionPerSec = tmp1; initialDelay = ((48000 * 24) + rate - 1) / rate; /* * Fill in the VariDecimate control block. */ spin_lock_irqsave(&card->lock, flags); cs461x_poke(card, BA1_CSRC, ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF)); cs461x_poke(card, BA1_CCI, coeffIncr); cs461x_poke(card, BA1_CD, (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80); cs461x_poke(card, BA1_CPI, phiIncr); spin_unlock_irqrestore(&card->lock, flags); /* * Figure out the frame group length for the write back task. Basically, * this is just the factors of 24000 (2^6*3*5^3) that are not present in * the output sample rate. */ frameGroupLength = 1; for (cnt = 2; cnt <= 64; cnt *= 2) { if (((rate / cnt) * cnt) != rate) frameGroupLength *= 2; } if (((rate / 3) * 3) != rate) { frameGroupLength *= 3; } for (cnt = 5; cnt <= 125; cnt *= 5) { if (((rate / cnt) * cnt) != rate) frameGroupLength *= 5; } /* * Fill in the WriteBack control block. */ spin_lock_irqsave(&card->lock, flags); cs461x_poke(card, BA1_CFG1, frameGroupLength); cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength)); cs461x_poke(card, BA1_CCST, 0x0000FFFF); cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000)); cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF); spin_unlock_irqrestore(&card->lock, flags); dmabuf->rate = rate; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) ); return rate;}/* prepare channel attributes for playback */ static void cs_play_setup(struct cs_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; unsigned int tmp, Count, playFormat; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()+\n") ); cs461x_poke(card, BA1_PVOL, 0x80008000); if(!dmabuf->SGok) cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf)); Count = 4; playFormat=cs461x_peek(card, BA1_PFIE); if ((dmabuf->fmt & CS_FMT_STEREO)) { playFormat &= ~DMA_RQ_C2_AC_MONO_TO_STEREO; Count *= 2; } else playFormat |= DMA_RQ_C2_AC_MONO_TO_STEREO; if ((dmabuf->fmt & CS_FMT_16BIT)) { playFormat &= ~(DMA_RQ_C2_AC_8_TO_16_BIT | DMA_RQ_C2_AC_SIGNED_CONVERT); Count *= 2; } else playFormat |= (DMA_RQ_C2_AC_8_TO_16_BIT | DMA_RQ_C2_AC_SIGNED_CONVERT); cs461x_poke(card, BA1_PFIE, playFormat); tmp = cs461x_peek(card, BA1_PDTC); tmp &= 0xfffffe00; cs461x_poke(card, BA1_PDTC, tmp | --Count); CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()-\n") );}struct InitStruct{ u32 long off; u32 long val;} InitArray[] = { {0x00000040, 0x3fc0000f}, {0x0000004c, 0x04800000}, {0x000000b3, 0x00000780}, {0x000000b7, 0x00000000}, {0x000000bc, 0x07800000}, {0x000000cd, 0x00800000}, };/* * "SetCaptureSPValues()" -- Initialize record task values before each * capture startup. */void SetCaptureSPValues(struct cs_card *card){ unsigned i, offset; CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()+\n") ); for(i=0; i<sizeof(InitArray)/sizeof(struct InitStruct); i++) { offset = InitArray[i].off*4; /* 8bit to 32bit offset value */ cs461x_poke(card, offset, InitArray[i].val ); } CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()-\n") );}/* prepare channel attributes for recording */static void cs_rec_setup(struct cs_state *state){ struct cs_card *card = state->card; struct dmabuf *dmabuf = &state->dmabuf; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n") ); SetCaptureSPValues(card); /* * set the attenuation to 0dB */ cs461x_poke(card, BA1_CVOL, 0x80008000); /* * set the physical address of the capture buffer into the SP */ cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->rawbuf)); CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()-\n") );}/* get current playback/recording dma buffer pointer (byte offset from LBA), called with spinlock held! */ static inline unsigned cs_get_dma_addr(struct cs_state *state){ struct dmabuf *dmabuf = &state->dmabuf; u32 offset; if ( (!(dmabuf->enable & DAC_RUNNING)) && (!(dmabuf->enable & ADC_RUNNING) ) ) { CS_DBGOUT(CS_ERROR, 2, printk( "cs46xx: ERROR cs_get_dma_addr(): not enabled \n") ); return 0; } /* * ganularity is byte boundry, good part. */ if(dmabuf->enable & DAC_RUNNING) { offset = cs461x_peek(state->card, BA1_PBA); } else /* ADC_RUNNING must be set */ { offset = cs461x_peek(state->card, BA1_CBA); } CS_DBGOUT(CS_PARMS | CS_FUNCTION, 9, printk("cs46xx: cs_get_dma_addr() %d\n",offset) ); offset = (u32)bus_to_virt((unsigned long)offset) - (u32)dmabuf->rawbuf; CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8, printk("cs46xx: cs_get_dma_addr()- %d\n",offset) ); return offset;}static void resync_dma_ptrs(struct cs_state *state){ struct dmabuf *dmabuf; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") ); if(state) { dmabuf = &state->dmabuf; dmabuf->hwptr=dmabuf->swptr = 0; dmabuf->pringbuf = 0; } CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") );} /* Stop recording (lock held) */static inline void __stop_adc(struct cs_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; unsigned int tmp; dmabuf->enable &= ~ADC_RUNNING; tmp = cs461x_peek(card, BA1_CCTL); tmp &= 0xFFFF0000; cs461x_poke(card, BA1_CCTL, tmp );}static void stop_adc(struct cs_state *state){ unsigned long flags; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()+ \n") ); spin_lock_irqsave(&state->card->lock, flags); __stop_adc(state); spin_unlock_irqrestore(&state->card->lock, flags); CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()- \n") );}static void start_adc(struct cs_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; unsigned long flags; unsigned int tmp; spin_lock_irqsave(&card->lock, flags); if (!(dmabuf->enable & ADC_RUNNING) && ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize) && dmabuf->ready) && ((card->pm.flags & CS46XX_PM_IDLE) || (card->pm.flags & CS46XX_PM_RESUMED)) ) { dmabuf->enable |= ADC_RUNNING; cs_set_divisor(dmabuf); tmp = cs461x_peek(card, BA1_CCTL); tmp &= 0xFFFF0000; tmp |= card->cctl; CS_DBGOUT(CS_FUNCTION, 2, printk( "cs46xx: start_adc() poke 0x%x \n",tmp) ); cs461x_poke(card, BA1_CCTL, tmp); } spin_unlock_irqrestore(&card->lock, flags);}/* stop playback (lock held) */static inline void __stop_dac(struct cs_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; unsigned int tmp; dmabuf->enable &= ~DAC_RUNNING; tmp=cs461x_peek(card, BA1_PCTL); tmp&=0xFFFF; cs461x_poke(card, BA1_PCTL, tmp);}static void stop_dac(struct cs_state *state){ unsigned long flags; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()+ \n") ); spin_lock_irqsave(&state->card->lock, flags); __stop_dac(state); spin_unlock_irqrestore(&state->card->lock, flags); CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()- \n") );} static void start_dac(struct cs_state *state){ struct dmabuf *dmabuf = &state->dmabuf; struct cs_card *card = state->card; unsigned long flags; int tmp; CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") ); spin_lock_irqsave(&card->lock, flags); if (!(dmabuf->enable & DAC_RUNNING) && ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) && ((card->pm.flags & CS46XX_PM_IDLE) || (card->pm.flags & CS46XX_PM_RESUMED)) ) { dmabuf->enable |= DAC_RUNNING; tmp = cs461x_peek(card, BA1_PCTL); tmp &= 0xFFFF; tmp |= card->pctl; CS_DBGOUT(CS_PARMS, 6, printk( "cs46xx: start_dac() poke card=0x%.08x tmp=0x%.08x addr=0x%.08x \n", (unsigned)card, (unsigned)tmp, (unsigned)card->ba1.idx[(BA1_PCTL >> 16) & 3]+(BA1_PCTL&0xffff) ) ); cs461x_poke(card, BA1_PCTL, tmp); } spin_unlock_irqrestore(&card->lock, flags); CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()- \n") );}#define DMABUF_MINORDER 1/* * allocate DMA buffer, playback and recording buffers are separate. */static int alloc_dmabuf(struct cs_state *state){ struct cs_card *card=state->card; struct dmabuf *dmabuf = &state->dmabuf; void *rawbuf = NULL; void *tmpbuff = NULL; int order; struct page *map, *mapend; unsigned long df; dmabuf->ready = dmabuf->mapped = 0; dmabuf->SGok = 0;/** check for order within limits, but do not overwrite value.*/ if((defaultorder > 1) && (defaultorder < 12)) df = defaultorder; else df = 2; for (order = df; order >= DMABUF_MINORDER; order--) if ( (rawbuf = (void *) pci_alloc_consistent( card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr))) break; if (!rawbuf) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n")); return -ENOMEM; } dmabuf->buforder = order; dmabuf->rawbuf = rawbuf; // Now mark the pages as reserved; otherwise the // remap_page_range() in cs46xx_mmap doesn't work. // 1. get index to last page in mem_map array for rawbuf. mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); // 2. mark each physical page in range as 'reserved'. for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++) cs4x_mem_map_reserve(map); CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, rawbuf) );/** only allocate the conversion buffer for the ADC*/ if(dmabuf->type == CS_TYPE_DAC) { dmabuf->tmpbuff = NULL; dmabuf->buforder_tmpbuff = 0; return 0; }/* * now the temp buffer for 16/8 conversions */ tmpbuff = (void *) pci_alloc_consistent( card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff); if (!tmpbuff) return -ENOMEM; CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n", PAGE_SIZE << order, order, tmpbuff) ); dmabuf->tmpbuff = tmpbuff; dmabuf->buforder_tmpbuff = order; // Now mark the pages as reserved; otherwise the // remap_page_range() in cs46xx_mmap doesn't work. // 1. get index to last page in mem_map array for rawbuf. mapend = virt_to_page(dmabuf->tmpbuff + (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1); // 2. mark each physical page in range as 'reserved'. for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++) cs4x_mem_map_reserve(map); return 0;}/* free DMA buffer */static void dealloc_dmabuf(struct cs_state *state){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -