📄 cs4281.c
字号:
writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch) // Set 'Half Terminal Count Interrupt Enable' and 'Terminal // Count Interrupt Enable' in DMA Control Registers 0 & 1. // Set 'MSK' flag to 1 to keep the DMA engines paused. temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h) writel(temp1, card->pBA0 + BA0_DCR0); // (154h writel(temp1, card->pBA0 + BA0_DCR1); // (15ch) // Set 'Auto-Initialize Control' to 'enabled'; For playback, // set 'Transfer Type Control'(TR[1:0]) to 'read transfer', // for record, set Transfer Type Control to 'write transfer'. // All other bits set to zero; Some will be changed @ transfer start. temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h) writel(temp1, card->pBA0 + BA0_DMR0); // (150h) temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h) writel(temp1, card->pBA0 + BA0_DMR1); // (158h) // Enable DMA interrupts generally, and // DMA0 & DMA1 interrupts specifically. temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff; writel(temp1, card->pBA0 + BA0_HIMR); CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n")); return 0;}//******************************************************************************// "cs4281_play_rate()" --//******************************************************************************static void cs4281_play_rate(struct cs4281_state *card, u32 playrate){ u32 DACSRvalue = 1; // Based on the sample rate, program the DACSR register. if (playrate == 8000) DACSRvalue = 5; if (playrate == 11025) DACSRvalue = 4; else if (playrate == 22050) DACSRvalue = 2; else if (playrate == 44100) DACSRvalue = 1; else if ((playrate <= 48000) && (playrate >= 6023)) DACSRvalue = 24576000 / (playrate * 16); else if (playrate < 6023) // Not allowed by open. return; else if (playrate > 48000) // Not allowed by open. return; CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n", DACSRvalue, playrate)); // Write the 'sample rate select code' // to the 'DAC Sample Rate' register. writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)}//******************************************************************************// "cs4281_record_rate()" -- Initialize the record sample rate converter.//******************************************************************************static void cs4281_record_rate(struct cs4281_state *card, u32 outrate){ u32 ADCSRvalue = 1; // // Based on the sample rate, program the ADCSR register // if (outrate == 8000) ADCSRvalue = 5; if (outrate == 11025) ADCSRvalue = 4; else if (outrate == 22050) ADCSRvalue = 2; else if (outrate == 44100) ADCSRvalue = 1; else if ((outrate <= 48000) && (outrate >= 6023)) ADCSRvalue = 24576000 / (outrate * 16); else if (outrate < 6023) { // Not allowed by open. return; } else if (outrate > 48000) { // Not allowed by open. return; } CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n", ADCSRvalue, outrate)); // Write the 'sample rate select code // to the 'ADC Sample Rate' register. writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)}static void stop_dac(struct cs4281_state *s){ unsigned long flags; unsigned temp1; CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n")); spin_lock_irqsave(&s->lock, flags); s->ena &= ~FMODE_WRITE; temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK; writel(temp1, s->pBA0 + BA0_DCR0); spin_unlock_irqrestore(&s->lock, flags);}static void start_dac(struct cs4281_state *s){ unsigned long flags; unsigned temp1; CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()+\n")); spin_lock_irqsave(&s->lock, flags); if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) { s->ena |= FMODE_WRITE; temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask. writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing. writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts. writel(7, s->pBA0 + BA0_PPRVC); writel(7, s->pBA0 + BA0_PPLVC); CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO "cs4281: start_dac(): writel 0x%x start dma\n", temp1)); } spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()-\n"));}static void stop_adc(struct cs4281_state *s){ unsigned long flags; unsigned temp1; CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: stop_adc()+\n")); spin_lock_irqsave(&s->lock, flags); s->ena &= ~FMODE_READ; if (s->conversion == 1) { s->conversion = 0; s->prop_adc.fmt = s->prop_adc.fmt_original; } temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK; writel(temp1, s->pBA0 + BA0_DCR1); spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: stop_adc()-\n"));}static void start_adc(struct cs4281_state *s){ unsigned long flags; unsigned temp1; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: start_adc()+\n")); spin_lock_irqsave(&s->lock, flags); if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count <= (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize)) && s->dma_adc.ready) { if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) { // // now only use 16 bit capture, due to truncation issue // in the chip, noticable distortion occurs. // allocate buffer and then convert from 16 bit to // 8 bit for the user buffer. // s->prop_adc.fmt_original = s->prop_adc.fmt; if (s->prop_adc.fmt & AFMT_S8) { s->prop_adc.fmt &= ~AFMT_S8; s->prop_adc.fmt |= AFMT_S16_LE; } if (s->prop_adc.fmt & AFMT_U8) { s->prop_adc.fmt &= ~AFMT_U8; s->prop_adc.fmt |= AFMT_U16_LE; } // // prog_dmabuf_adc performs a stop_adc() but that is // ok since we really haven't started the DMA yet. // prog_codec(s, CS_TYPE_ADC); if (prog_dmabuf_adc(s) != 0) { CS_DBGOUT(CS_ERROR, 3, printk(KERN_INFO "cs4281: start_adc(): error in prog_dmabuf_adc\n")); } s->conversion = 1; } s->ena |= FMODE_READ; temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK; // Clear DMA1 channel mask bit. writel(temp1, s->pBA0 + BA0_DCR1); // Start recording writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts. CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO "cs4281: start_adc(): writel 0x%x \n", temp1)); } spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: start_adc()-\n"));}// --------------------------------------------------------------------- // use 64k (+1) rather than 32k as some of the higher frequencies need a larger buffer.// comments reflect 32k.#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT+1) // == 3(for PC), = log base 2( buff sz = 32k).#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db){ struct page *map, *mapend; if (db->rawbuf) { // Undo prog_dmabuf()'s marking the pages as reserved mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); for (map = virt_to_page(db->rawbuf); map <= mapend; map++) mem_map_unreserve(map); pci_free_consistent(s->pcidev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr); } if (s->tmpbuff && (db->type == CS_TYPE_ADC)) { // Undo prog_dmabuf()'s marking the pages as reserved mapend = virt_to_page(s->tmpbuff + (PAGE_SIZE << s->buforder_tmpbuff) - 1); for (map = virt_to_page(s->tmpbuff); map <= mapend; map++) mem_map_unreserve(map); pci_free_consistent(s->pcidev, PAGE_SIZE << s->buforder_tmpbuff, s->tmpbuff, s->dmaaddr_tmpbuff); } s->tmpbuff = NULL; db->rawbuf = NULL; db->mapped = db->ready = 0;}static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db){ int order; unsigned bytespersec, temp1; unsigned bufs, sample_shift = 0; struct page *map, *mapend; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_dmabuf()+\n")); db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = db->blocks = db->wakeup = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) if ( (db->rawbuf = (void *) pci_alloc_consistent(s->pcidev, PAGE_SIZE << order, &db-> dmaaddr))) break; if (!db->rawbuf) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: prog_dmabuf(): unable to allocate rawbuf\n")); return -ENOMEM; } db->buforder = order; // Now mark the pages as reserved; otherwise the // remap_page_range() in cs4281_mmap doesn't work. // 1. get index to last page in mem_map array for rawbuf. mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); // 2. mark each physical page in range as 'reserved'. for (map = virt_to_page(db->rawbuf); map <= mapend; map++) mem_map_reserve(map); } if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) { for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) if ( (s->tmpbuff = (void *) pci_alloc_consistent(s->pcidev, PAGE_SIZE << order, &s-> dmaaddr_tmpbuff))) break; if (!s->tmpbuff) { CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n")); return -ENOMEM; } s->buforder_tmpbuff = order; // Now mark the pages as reserved; otherwise the // remap_page_range() in cs4281_mmap doesn't work. // 1. get index to last page in mem_map array for rawbuf. mapend = virt_to_page(s->tmpbuff + (PAGE_SIZE << s->buforder_tmpbuff) - 1); // 2. mark each physical page in range as 'reserved'. for (map = virt_to_page(s->tmpbuff); map <= mapend; map++) mem_map_reserve(map); } if (db->type == CS_TYPE_DAC) { if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE)) sample_shift++; if (s->prop_dac.channels > 1) sample_shift++; bytespersec = s->prop_dac.rate << sample_shift; } else // CS_TYPE_ADC { if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE)) sample_shift++; if (s->prop_adc.channels > 1) sample_shift++; bytespersec = s->prop_adc.rate << sample_shift; } bufs = PAGE_SIZE << db->buforder;#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds. db->numfrag = 2; temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS); // Nominal frag size(bytes/interrupt) db->fragshift = 8; // Min 256 bytes. while (1 << db->fragshift < temp1) // Calc power of 2 frag size. db->fragshift += 1; db->fragsize = 1 << db->fragshift; db->dmasize = db->fragsize * 2; db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.// If the calculated size is larger than the allocated// buffer, divide the allocated buffer into 2 fragments. if (db->dmasize > bufs) { db->numfrag = 2; // Two fragments. db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer. db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment. db->dmasize = bufs; // Use all the alloc'ed buffer. db->fragshift = 0; // Calculate 'fragshift'. temp1 = db->fragsize; // update_ptr() uses it while ((temp1 >>= 1) > 1) // to calc 'total-bytes' db->fragshift += 1; // returned in DSP_GETI/OPTR. } CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_dmabuf()-\n")); CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n", db->numfrag, db->fragsize, db->fragsamples, db->fragshift, bufs, (db->type == CS_TYPE_DAC) ? s->prop_dac.fmt : s->prop_adc.fmt, (db->type == CS_TYPE_DAC) ? s->prop_dac.channels : s-> prop_adc.channels)); return 0;}static int prog_dmabuf_adc(struct cs4281_state *s){ unsigned long va; unsigned count; int c; stop_adc(s); s->dma_adc.type = CS_TYPE_ADC; if ((c = prog_dmabuf(s, &s->dma_adc))) return c; if (s->dma_adc.rawbuf) { memset(s->dma_adc.rawbuf, (s->prop_adc. fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, s->dma_adc.dmasize); } if (s->tmpbuff) { memset(s->tmpbuff, (s->prop_adc. fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, PAGE_SIZE << s->buforder_tmpbuff); } va = virt_to_bus(s->dma_adc.rawbuf); count = s->dma_adc.dmasize; if (s->prop_adc. fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) count /= 2; // 16-bit. if (s->prop_adc.channels > 1) count /= 2; // Assume stereo. CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n", count, (unsigned) va)); writel(va, s->pBA0 + BA0_DBA1); // Set buffer start address. writel(count - 1, s->pBA0 + BA0_DBC1); // Set count. s->dma_adc.ready = 1; return 0;}static int prog_dmabuf_dac(struct cs4281_state *s)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -