📄 cs4281m.c
字号:
// --------------------------------------------------------------------- #define DMABUF_MINORDER 1 // ==> min buffer size = 8K.static 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++) ClearPageReserved(map); free_dmabuf(s, db); } 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++) ClearPageReserved(map); free_dmabuf2(s, db); } 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_pfn_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++) SetPageReserved(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_pfn_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++) SetPageReserved(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 %p for %d size \n", (unsigned)c, ((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=%p hwptr=%d total_bytes=%d count=%d \n", 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 %p for %d size \n", (unsigned)(s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, 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_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n", s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count)); }}// --------------------------------------------------------------------- static void prog_codec(struct cs4281_state *s, unsigned type){ unsigned long flags; unsigned temp1, format; CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_codec()+ \n")); spin_lock_irqsave(&s->lock, flags); if (type == CS_TYPE_ADC) { temp1 = readl(s->pBA0 + BA0_DCR1); writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1); // Stop capture DMA, if active. // program sampling rates // Note, for CS4281, capture & play rates can be set independently. cs4281_record_rate(s, s->prop_adc.rate); // program ADC parameters format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE; if (s->prop_adc. fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian? format |= DMRn_BEND; if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE)) format |= DMRn_USIGN; // Unsigned. } else format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned if (s->prop_adc.channels < 2) format |= DMRn_MONO; writel(format, s->pBA0 + BA0_DMR1); CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n", (format & DMRn_SIZE8) ? "8" : "16", (format & DMRn_USIGN) ? "Unsigned" : "Signed", (format & DMRn_MONO) ? "Mono" : "Stereo", s->prop_adc.rate, format)); s->ena &= ~FMODE_READ; // not capturing data yet } if (type == CS_TYPE_DAC) { temp1 = readl(s->pBA0 + BA0_DCR0); writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0); // Stop play DMA, if active. // program sampling rates // Note, for CS4281, capture & play rates can be set independently. cs4281_play_rate(s, s->prop_dac.rate); // program DAC parameters format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ; if (s->prop_dac. fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -