📄 cs4281m.c
字号:
CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: start_adc()+\n")); 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#ifndef NOT_CS4281_PM && (s->pm.flags & CS4281_PM_IDLE))#else ) #endif { 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, 2, printk(KERN_INFO "cs4281: start_adc(): error in prog_dmabuf_adc\n")); } s->conversion = 1; } spin_lock_irqsave(&s->lock, flags); 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. spin_unlock_irqrestore(&s->lock, flags); CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO "cs4281: start_adc(): writel 0x%x \n", temp1)); } CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: start_adc()-\n"));}// --------------------------------------------------------------------- #define DMABUF_MINORDER 0 // ==> 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++) cs4x_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++) cs4x_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; unsigned long df; 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 = db->underrun = 0;/** check for order within limits, but do not overwrite value, check* later for a fractional defaultorder (i.e. 100+).*/ if((defaultorder >= 0) && (defaultorder < 12)) df = defaultorder; else df = 1; if (!db->rawbuf) { db->ready = db->mapped = 0; for (order = df; 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++) cs4x_mem_map_reserve(map); } if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) { for (order = df; 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++) cs4x_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;/** added fractional "defaultorder" inputs. if >100 then use * defaultorder-100 as power of 2 for the buffer size. example:* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.*/ if(defaultorder >= 100) { bufs = 1 << (defaultorder-100); }#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds. db->numfrag = 2;/* * Nominal frag size(bytes/interrupt)*/ temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS); 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_PARMS, 3, 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)); CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_dmabuf()-\n")); 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){ unsigned long va; unsigned count; int c; stop_dac(s); s->dma_dac.type = CS_TYPE_DAC; if ((c = prog_dmabuf(s, &s->dma_dac))) return c; memset(s->dma_dac.rawbuf, (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, s->dma_dac.dmasize); va = virt_to_bus(s->dma_dac.rawbuf); count = s->dma_dac.dmasize; if (s->prop_dac. fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) count /= 2; // 16-bit. if (s->prop_dac.channels > 1) count /= 2; // Assume stereo. writel(va, s->pBA0 + BA0_DBA0); // Set buffer start address. writel(count - 1, s->pBA0 + BA0_DBC0); // Set count. CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n", count, (unsigned) va)); s->dma_dac.ready = 1; return 0;}static void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c){ if (bptr + len > bsize) { unsigned x = bsize - bptr; memset(((char *) buf) + bptr, c, x); bptr = 0; len -= x; } CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO "cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n", (unsigned)c, (unsigned)((char *) buf) + bptr, len)); memset(((char *) buf) + bptr, c, len);}// call with spinlock held! static void cs4281_update_ptr(struct cs4281_state *s, int intflag){ int diff; unsigned hwptr, va; // update ADC pointer if (s->ena & FMODE_READ) { hwptr = readl(s->pBA0 + BA0_DCA1); // Read capture DMA address. va = virt_to_bus(s->dma_adc.rawbuf); hwptr -= (unsigned) va; diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; s->dma_adc.hwptr = hwptr; s->dma_adc.total_bytes += diff; s->dma_adc.count += diff; if (s->dma_adc.count > s->dma_adc.dmasize) s->dma_adc.count = s->dma_adc.dmasize; if (s->dma_adc.mapped) { if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) wake_up(&s->dma_adc.wait); } else { if (s->dma_adc.count > 0) wake_up(&s->dma_adc.wait); } CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", (unsigned)s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count)); } // update DAC pointer // // check for end of buffer, means that we are going to wait for another interrupt // to allow silence to fill the fifos on the part, to keep pops down to a minimum. // if (s->ena & FMODE_WRITE) { hwptr = readl(s->pBA0 + BA0_DCA0); // Read play DMA address. va = virt_to_bus(s->dma_dac.rawbuf); hwptr -= (unsigned) va; diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; s->dma_dac.hwptr = hwptr; s->dma_dac.total_bytes += diff; if (s->dma_dac.mapped) { s->dma_dac.count += diff; if (s->dma_dac.count >= s->dma_dac.fragsize) { s->dma_dac.wakeup = 1; wake_up(&s->dma_dac.wait); if (s->dma_dac.count > s->dma_dac.dmasize) s->dma_dac.count &= s->dma_dac.dmasize - 1; } } else { s->dma_dac.count -= diff; if (s->dma_dac.count <= 0) { // // fill with silence, and do not shut down the DAC. // Continue to play silence until the _release. // CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO "cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n", (unsigned)(s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, (unsigned)s->dma_dac.rawbuf, s->dma_dac.dmasize)); memset(s->dma_dac.rawbuf, (s->prop_dac. fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, s->dma_dac.dmasize); if (s->dma_dac.count < 0) { s->dma_dac.underrun = 1; s->dma_dac.count = 0; CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO "cs4281: cs4281_update_ptr(): underrun\n")); } } else if (s->dma_dac.count <= (signed) s->dma_dac.fragsize && !s->dma_dac.endcleared) { clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr, s->dma_dac.fragsize, (s->prop_dac. fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0); s->dma_dac.endcleared = 1; } if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) || intflag) { wake_up(&s->dma_dac.wait); } } CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO "cs4281: cs4281_update_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -